はじめに
VALU Advent Calendar 2018 の17日目です。
Advent Calendar なるものに初めて参加したのですが…ちょっとドキドキです!
今回は今更感が満載ですが RecyclerView のあるある実装が簡単になる Groupie を使ってヘッダーのあるリストを作成したいと思います。
手順
Groupie のサンプルプロジェクト groupie/example-databinding を参考にして実装していきます。
- レイアウトを作成
- ViewHolder を作成
- RecyclerView に add
Step1
RecyclerView に表示するレイアウトを作成します。
ヘッダー
<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="viewModel"
type="me.aluceps.practicerecyclerview.ItemViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<TextView android:id="@+id/item_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@{viewModel.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="ヘッダー1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
アイテム
<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="viewModel"
type="me.aluceps.practicerecyclerview.ItemViewModel"
/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView android:id="@+id/item_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:padding="16dp"
android:text="@{viewModel.text}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="アイテム1"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Binding させる ViewModel は ObservableField を1つ持つだけのクラスです。
class ItemViewModel : BaseObservable() {
val text: ObservableField<String> = ObservableField()
}
Step2
ヘッダーとアイテムの ViewHolder を作成します。
ヘッダー
class ItemHeaderViewHolder(id: Long) : BindableItem<ItemHeaderBinding>(id) {
private val viewModel = ItemViewModel()
override fun getLayout(): Int = R.layout.item_header
override fun bind(viewBinding: ItemHeaderBinding, position: Int) {
viewBinding.viewModel = viewModel
}
fun setText(value: String) {
viewModel.text.set(value)
viewModel.notifyChange()
}
}
アイテム
class ItemNormalViewHolder(id: Long) : BindableItem<ItemNormalBinding>(id) {
private val viewModel = ItemViewModel()
override fun getLayout(): Int = R.layout.item_normal
override fun bind(viewBinding: ItemNormalBinding, position: Int) {
viewBinding.viewModel = viewModel
}
fun setText(value: String) {
viewModel.text.set(value)
viewModel.notifyChange()
}
}
Step3
これまで作成したヘッダーとアイテムを使って RecyclerView に追加する処理を書きます。
private var groupAdapter: GroupAdapter<ViewHolder>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
groupAdapter = GroupAdapter()
initializeRecyclerView()
for (i in 1..5) addItems(i)
}
private fun initializeRecyclerView() {
binding.recyclerView.run {
adapter = groupAdapter
layoutManager = LinearLayoutManager(this@MainActivity)
addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL))
}
}
private fun addItems(index: Int) {
val section = Section()
section.setHeader(ItemHeaderViewHolder(index.toLong()).apply { setText("Section No.$index") })
for (i in 1..20) section.add(ItemNormalViewHolder(i.toLong()).apply { setText("Section No:$index Row:$i") })
groupAdapter?.add(section)
}
Groupie は Section という単位でヘッダーとアイテムを追加していきます。Section.setHeader()
でヘッダーを追加し Section.add()
でアイテムを追加しています。そして GroupAdapter に追加することでヘッダーとアイテムの組み合わせを RecyclerView で表現できるようです。とても簡単ですね。
イメージ
まとめ
Groupie を使うことでわずか3ステップでヘッダーとリストのある RecyclerView ができました。Groupie を使わずに手作りした場合は Adapter の作成が必要になる上に ViewType に応じた処理を書く必要があります。難しいわけではないのですが ViewType を追加するたびに書くのは結構面倒なんですよね…!
そういった手間を省くことができるので Groupie はとてもオススメです!