listviewの表示をDataBindigを使ってみることにしました。
もともと、android.R.layout.simple_expandable_list_item_2
というオープンソースを使っていたのですが、カスタマイズできないのと、カスタマイズするならDataBindingを使ってみようと思ったのが、キッカケです。
####①build.gradleに設定の追加
まずはDataBindigを使えるように設定を追加します。
// 追加
apply plugin: 'kotlin-kapt'
android {
// 追加
dataBinding {
enabled = true
}
}
####②レイアウトの作成
次にレイアウトの作成を行います。
<?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>
<variable
name="taskDetail"
type="com.kumaydevelop.todoreminder.Model.TaskDetail" />
</data>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{taskDetail.title}"/>
<TextView
android:id="@+id/limit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{taskDetail.limit}"/>
</LinearLayout>
</layout>
手順としては、最初のタグをLayoutタグで括り、dataタグを追加します。
variable属性のnameが今回の場合はtext属性を表示するために使われています。
今回は省略しますが、variable属性のtypeがモデルとなります。
####③Adapterの作成
次にAdapterを作成します。普通にlistViewを作成する場合でも作るのですが、少し異なります。
class TaskAdapter(val context: Context) : BaseAdapter() {
var tasks: List<TaskDetail> = emptyList()
override fun getCount(): Int {
return tasks.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItem(position: Int): Any {
return tasks[position]
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var binding: TaskItemBinding?
if (convertView == null) {
// カスタム作成したtask_item.xmlを使う
binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.task_item,parent,false)
binding.root.tag = binding
} else {
// 今まで使っていたものを使いまわす
binding = convertView.tag as TaskItemBinding
}
binding!!.taskDetail = getItem(position) as TaskDetail
// root化してviewを返す
return binding.root
}
}
ここで使われている、TaskItemBinding
は②で作成したxmlがあれば使えるはずです。
もしくはビルドしてください。
今回はtask_item.xmlなので、xmlを除いた末尾からの名前で作成されるはずです。
流れとしては下記になります。
①getViewでconvertViewがnullの時にBookItemBindingクラスを作成。それ以外の時は使い回す
②getViewの戻りはBookItemBindingのインスタンスのrootすることでViewが返る
viewHolderが必要なくなりましたね!
こちらの方が直感的に見やすい印象があります。
####④Activityとの連携
最後に③で作ったものをActivityと連携させます。
今回はActivityもDataBindingを使っています。
<?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">
<data>
<variable
name="onItemClick"
type="android.widget.AdapterView.OnItemClickListener" />
</data>
<android.support.design.widget.CoordinatorLayout
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Activity.MainActivity">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:onItemClickListener="@{onItemClick}"/>
</android.support.design.widget.CoordinatorLayout>
</layout>
次にMainActivityで連携させます。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
val binding : ActivityMainBinding
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val listAdapter = TaskAdapter(applicationContext)
// 省略していますが、taskListは表示させるデータのリストです。
listAdapter.tasks = taskList
binding.listview.adapter = listAdapter
}
ここは、DataBindingを使わなくでもあまり変わらないと思います。
違うのが、DataBindingUtil
を使って、Bidingクラスを取得してxmlで定義してある必要なデータをセットするところと、binding.listview.adapter = listAdapter
でActivityMainBindingのlistViewにAdapterをセットしているところです。
実際に使ってみて、web開発の経験がある人は画面に変数をセットするのはなじみがあって、導入しやすい気がしました。
####参照
Kotlin × Data BindingでonItemClickListener付きListViewアプリを作る