GroupieのVIewHolderを使ってみた

自分のブログから引っ張ってきました.
https://wally-ngm.hatenablog.com/entry/2020/06/05/222302

GroupieのViewHolderを試してみました.
[https://github.com/lisawray/groupie/releases:embed:cite]


GroupieはAndroidのrecycler-viewを楽に使えるようにするライブラリですが, groupie-databindingがdeprecatedされました.

今回は推奨されてる(ぽい)groupie-viewbindingを使ってみたいと思います.


#### 1. Groupieを追加
基本的にはgithubの[Gradle Setup](https://github.com/lisawray/groupie#gradle-setup)を見れば大丈夫で, モジュールレベルのbuild.gradleに以下を追加すればOKです.

```
android {
    ....
    androidExtensions {
        experimental = true
    }
    viewBinding {
        enabled = true
    }
}

dependencies {
    ....
    def groupie_version = "2.8.0"
    implementation "com.xwray:groupie:$groupie_version"
    implementation "com.xwray:groupie-kotlin-android-extensions:$groupie_version"
    implementation "com.xwray:groupie-viewbinding:$groupie_version"
}
```


追加で, 2020年6月5日現在, 以下のようなエラーが出てくるので少しだけ対応が必要でした.
```
ERROR: Failed to resolve: com.xwray:groupie-viewbinding:2.8.0
```

ISSUEによれば, リリースされて間もないからエラーでてるらしいです.
プロジェクトレベルのbuild.gradleに1行追加して対応します.
```
allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://dl.bintray.com/lisawray/maven' } // この行を追加
    }
}
```


#### 2. リスト表示するアイテムを作成する
リストのアイテムとなるクラスとレイアウトファイルを作成します.

クラスはこんな感じで, `bind`メソッドでview-bindingを使えば良さそうです. 楽ちんですね.
```TopListItem.kt
package wally.wally.android_practice

import android.view.View
import com.xwray.groupie.viewbinding.BindableItem
import wally.wally.android_practice.databinding.ItemTopListBinding

class TopListItem(private val text: String) : BindableItem<ItemTopListBinding>() {
    override fun getLayout() = R.layout.item_top_list

    override fun bind(viewBinding: ItemTopListBinding, position: Int) {
        viewBinding.button.text = text
    }

    override fun initializeViewBinding(view: View): ItemTopListBinding {
        return ItemTopListBinding.bind(view)
    }
}
```

xmlはこんな感じ.
```item_top_list.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="wrap_content">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button"
            style="@style/Widget.MaterialComponents.Button.OutlinedButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@color/white"
            android:text=""
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:backgroundTint="@color/primaryLight"
            tools:text="ボタン" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
```


今回は何を思ったのかマテリアルデザインのボタンを使ってしまいました.
このボタンは, アクティビティにマテリアルコンポーネントのテーマを適用させる必要があるみたいでしたので, Manifestファイルも少しいじります
リストのアイテムにマテリアルボタンを使わないなら必要ありません.
```
<activity
            android:name=".MainActivity"
            android:theme="@style/Theme.MaterialComponents.Light" <= マテリアルボタンを設置する場合はテーマを適用
            tools:ignore="LockedOrientationActivity"
```


#### 3. recycler-viewを設置してリストを表示させる

xmlの方にrecycler-viewを設置します.
```
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recycler_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
```


MainActivityの方で, GroupieAdapterを作成して, それをrecyclerViewのアダプターとします.
```
package wally.wally.android_practice

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.xwray.groupie.GroupAdapter
import com.xwray.groupie.GroupieViewHolder
import wally.wally.android_practice.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        val adapter = GroupAdapter<GroupieViewHolder>()
        binding.recyclerView.adapter = adapter
        binding.lifecycleOwner = this
        binding.recyclerView.layoutManager = LinearLayoutManager(this)

        adapter.update((1..30).map { TopListItem("テストボタン${it}") })
        adapter.add(TopListItem("テストボタンファイナル"))
    }
}

```


大事なのはここです.
recyclerVIewにはレスポンシブに対応するためのlayoutManagerが存在しますのでこちらも設定する必要があります.
リストをまとめて渡すだけで表示してくれますし, 1つだけ追加したい場合は `add` メソッドを使ってあげればいいです(この辺はview-holderというよりgroupieの機能)

```
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val adapter = GroupAdapter<GroupieViewHolder>()
binding.recyclerView.adapter = adapter
binding.lifecycleOwner = this
binding.recyclerView.layoutManager =  LinearLayoutManager(this)

adapter.update((1..30).map { TopListItem("テストボタン${it}") })
adapter.add(TopListItem("テストボタンファイナル"))
```



最終的にこんな風に表示されます
![結果](https://cdn-ak.f.st-hatena.com/images/fotolife/u/ustrgm/20200605/20200605221819.png)