はじめに
以下のようなListViewを使ったメニュー画面を作るときに、
項目ごとに実行される処理が異なるので、
その処理部分を関数オブジェクト化してみたら、
一元管理できて便利だったのでまとめておきます。
レポジトリ
利用技術
- DataBinding
- DataBinding-ktx(https://github.com/wada811/DataBinding-ktx)
MainActivity
MainActivity.kt
class MainActivity : AppCompatActivity() {
// wada811さんのDataBinding-ktxを使っています。
// DataBinding-ktxを使うとonCreaete内のbindingの初期化コードが不要になります。
//
// https://github.com/wada811/DataBinding-ktx
//
// private lateinit var binding: ActivityMainBinding
private val binding by viewBinding { ActivityMainBinding.inflate(it) }
companion object {
// メニュー画面のリストに表示するラベルと
// タップされたときに実行する処理の定義
val listItems = listOf(
MyMenuItem("Toast表示") { activity->
Toast.makeText(activity, "Toast Test", Toast.LENGTH_LONG).show()
},
MyMenuItem("何もしない"),
MyMenuItem("アプリ終了") { activity->
activity.finish()
}
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
// binding.lifecycleOwner = this
val adapter = MyMenuListAdapter(this, listItems)
binding.listView.adapter = adapter
// リスト項目がタップされたときの処理
binding.listView.setOnItemClickListener { parent, view, position, id ->
val menuItem = listItems[position]
// menuItemにセットされている関数オブジェクトを実行する
menuItem.executeBlock?.invoke(this)
}
}
}
Databindingの初期化にwada811さんのDataBinding-ktxを使っている以外は特別な事はしてません。
やってる事は以下の3つです。
- ListView用のカスタムArrayAdapter(MyMenuListAdapter)を作る
- ListViewにカスタムArrayAdapterをセットする
- ListViewの項目がタップされた処理を設定する
メニュー画面に表示するリストの定義部分
MainActivity_listItems
companion object {
// メニュー画面のリストに表示するラベルと
// タップされたときに実行する処理の定義
val listItems = listOf(
MyMenuItem("Toast表示") { activity->
Toast.makeText(activity, "Toast Test", Toast.LENGTH_LONG).show()
},
MyMenuItem("何もしない"),
MyMenuItem("アプリ終了") { activity->
activity.finish()
}
)
}
companion objectに定義しているlistItemsがメニュー画面に表示するリストの定義です。
画面に表示されるラベルと、項目をタップした時に実行される処理をラムダで記述してあります。
MyMenuItem
MyMenuItem.kt
class MyMenuItem(
// リスト項目に表示されるラベル
val label: String,
// リスト項目をタップしたときに実行される処理
val executeBlock: ((activity: Activity) -> Unit?)? = null
)
コンストラクタ引数executeBlockの型は関数オブジェクトで、
その関数オブジェクトの引数はActivityで、
その関数オブジェクトの戻り値はUnitです。
ListViewのタップ処理
MainActivity_onCreate
// リスト項目がタップされたときの処理
binding.listView.setOnItemClickListener { parent, view, position, id ->
val menuItem = listItems[position]
// menuItemにセットされている関数オブジェクトを実行する
menuItem.executeBlock?.invoke(this)
}
ここが核心部分です。
ListViewの項目がタップされると、このリスナが呼び出されるので、
positionから対応するMyMenuItemを取り出して、
MyMenuItemのインスタンスに定義されている関数オブジェクトを実行しています。
関数オブジェクトの引数thisにはactivityを渡しています。
MyMenuListAdapter
MyMenuListAdapter
class MyMenuListAdapter(
context: Context,
menuList: List<MyMenuItem>,
private val onClickListener: ((View, MyMenuItem) -> Unit)? = null
) : ArrayAdapter<MyMenuItem>(context, 0, menuList) {
private val inflater = LayoutInflater.from(context)
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val binding =
if (convertView == null) {
val tmpBinding: MenuListItemBinding = DataBindingUtil.inflate(
inflater,
R.layout.menu_list_item,
parent,
false
)
tmpBinding.root.tag = tmpBinding
tmpBinding
} else {
convertView.tag as MenuListItemBinding
}
binding.menuItem = getItem(position)
return binding.root
}
}
ListView用のDataBindingを使ったArrayAdapterです。
ここは特別なことはやってません。
画面のlayout定義とかその他
activity_main.xml(layout)
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
ListViewが1つあるだけの画面です。
menu_list_item.xml(layout)
menu_list_item
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="menuItem"
type="io.github.cnaos.example.listmenuexample.MyMenuItem" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/menu_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:text="@{menuItem.label}"
android:textSize="18sp" />
</LinearLayout>
</layout>
ListViewの各項目の表示に使われるlayoutの定義です。