DataBinding で ViewHolder パターンを書き直してみた
ListView と DataBinding を組み合わせてガリガリ書いてましたが、RecyclerView に置き換えて使わなくなってしまったので供養のための投稿です。
完全にメモなので詳細な説明はなし……すみません(; ˘ω˘)
言語は Kotlin です。
data class 定義
ListView に表示する項目の data class を適当に定義。
data class Record(...)
xml
ListView のアイテムのレイアウトに Record クラスをバインドする。Glide 使ってるので、ImageView にカスタムセッターとしてandroid:image_url
定義しています。
バインドしたら念のためリビルド。
<layout> <data> <variable name="record" type="Record" /> </data> <ConstraintLayout... > <ImageView #カスタムセッター android:image_url="@{record.imageUrl}" /> <TextView android:text="@{record.recordedTime}" /> <TextView android:text="@{record.comment}" /> </ConstraintLayout> </layout>
カスタムセッターを拡張関数で定義。
@BindingAdapter("android:image_url") fun ImageView.setImageUrl(url: String) { Glide.with(context).load(url).into(this) }
Adapter 定義
Adapter クラスを定義。
ViewHolder パターンでは内部的に ViewHolder クラスを定義して findViewById
でView を取得していましたが、DataBinding を利用して構築すると不要になります。
class RecordAdapter(context: Context) : ArrayAdapter<Record>(...) { private val inflater = ... //Inflater生成 private lateinit var binding: RecordItemBinding //自動生成されるクラス override fun getView(..., convertView: View?, ...): View { when (convertView) { null -> { binding = DataBindingUtil.inflate(inflater, R.layout.record_item, parent, false) binding.root.tag = binding } else -> binding = convertView.tag as RecordItemBinding } val record = this.getItem(position) if (record != null){ binding.record = record } return binding.root } }
あとは普通に ListView に RecordAdapter をセットすれば大丈夫、なはず。不足してたら後で追記します。
アレだったら、ListView に@BindingAdapter("bind:adapter")
等で拡張関数を定義すればもっと簡単になると思います。
では。