入社して3ヶ月経ちそうですが、まだEpoxyを触ったことなかったので備忘録として書いていきます。
Epoxyを使うとRecyclerViewを簡単に実装できるみたいです!(中毒性があるので注意らしい)
実装
##Gradle
まずはEpoxyを使うためにGradleに依存関係を記述します。
def epoxy_version = "3.11.0"
implementation "com.airbnb.android:epoxy:$epoxy_version"
// databinding使用するなら
implementation "com.airbnb.android:epoxy-databinding:${epoxy_version}"
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
package-info
gradleに依存関係を記述したら、package-info.java
ファイルをプロジェクト内に作成します。
@EpoxyDataBindingLayouts({R.layout.recyclerview_item})
package com.example.todo;
import com.airbnb.epoxy.EpoxyDataBindingLayouts;
@EpoxyDataBindingLayouts
アノテーションでレイアウトファイルを指定するとModelが自動生成してくれます。
ここで一旦ビルドをかけてください。
layout
過去の記事のxmlファイルをDataBindingするために<layout>
属性で囲います。後に書くControllerからTodoTitleを受け取って表示させます。
<?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="todoTitle"
type="String" />
</data>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:foreground="?android:attr/selectableItemBackground"
app:cardElevation="10dp">
<LinearLayout
android:id="@+id/LinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@android:color/white"
android:orientation="horizontal">
<ImageView
android:id="@+id/sampleImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:contentDescription="@string/recycler_picture"
app:srcCompat="@mipmap/ic_launcher_round" />
<TextView
android:id="@+id/sampleTxt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@{ todoTitle }"
tools:text="TODO"
android:textSize="30sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</layout>
Controller
Controllerは引数が一つの時はTypedEpoxyController<List<Todo>>()
を継承します。
これは引数2つの場合は、Typed2EpoxyController()
3つ、Typed3EpoxyController()
4つ、Typed4EpoxyController()
今回は、表示するリストだけをもらえればいいので、TypedEpoxyController()
を選択しました。
class RecyclerViewController(
lifecycleOwner: LifecycleOwner,
viewModel: MainViewModel
) : TypedEpoxyController<List<Todo>>() {
init {
viewModel.todoList.observe(lifecycleOwner, ::setData)
}
override fun buildModels(data: List<Todo>?) {
data?.forEach {
recyclerviewItem {
id(modelCountBuiltSoFar)
todoTitle(it.todoTitle)
}
}
}
}
順を追ってControllerを見ていきましょう。buildModels()
はsetData()
が呼ばれると実行されます。そのため今回はRoomに保存しているLiveDataが更新させるたびにsetData()
を呼ぶようにObserveを書きました。
buildModels()
内に表示させるものを書いていきます。引数でもらったdataを自動生成された拡張関数recyclerviewItemで表示させます。
inline fun ModelCollector.recyclerviewItem(
modelInitializer: RecyclerviewItemBindingModelBuilder.() -> Unit
) {
add(
RecyclerviewItemBindingModel_().apply {
modelInitializer()
}
)
}
毎回add()
を書かずに済むのでとても便利ですね!(これが自動生成されるなんて)
id()
とは、表示される要素毎に重複しないものを設定して上げる必要があります。これを指定すると表示させる要素の差分などを判別してくれるらしい。とりあえず被らないようにmodelCountBuiltSoFar
を入れました。これは、Epoxyで表示させている要素の数です。idの付け方で迷ったらこれにしてます。
Activity
あとは同じみの記述をするだけでリスト表示ができました! ViewHolderやらを書かなくて済むのはとてもいい感じです。
recyclerViewController = RecyclerViewController(this, mainViewModel)
main_recycler_view.apply {
this.adapter = recyclerViewController.adapter
this.layoutManager = LinearLayoutManager(this@MainActivity)
}