Edited at
VALUDay 17

Groupie をつかってみる


はじめに

VALU Advent Calendar 2018 の17日目です。

Advent Calendar なるものに初めて参加したのですが…ちょっとドキドキです!

今回は今更感が満載ですが RecyclerView のあるある実装が簡単になる Groupie を使ってヘッダーのあるリストを作成したいと思います。


手順

Groupie のサンプルプロジェクト groupie/example-databinding を参考にして実装していきます。


  1. レイアウトを作成

  2. ViewHolder を作成

  3. 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 はとてもオススメです!