EpoxyRecyclerViewの一部にComposeを使用する
初めに
ポートでAndroid開発をしている @shxun6934 です。
今回は、com.airbnb.android:epoxy-compose
を使用して、EpoxyRecyclerViewの一部にJetpackCompose(以下Composeと呼ぶ)を使用する方法を書きたいと思います。
Epoxyとは
Airbnbが提供している、RecyclerViewを簡単に構築することができるAndroidライブラリです。
RecyclerViewについては、Google公式のドキュメントがあるので、そちらをみてください。
RecyclerViewを構築する際は、AdapterとViewHolderを実装する必要がありますが、Epoxyがそれらの代わりに実装をしてくれるので、簡単に実装ができます。
代わりに実装者は、EpoxyModelとEpoxyControllerを実装して、RecyclerViewの制御を行います。
Epoxyは、data-bindingにも対応をしていて、専用のアノテーション(@EpoxyDataBindingLayouts)を使用しているとEpoxyModelとEpoxyControllerも自動で生成してくれるので、もっと簡単に実装できます。
詳しい内容は、GithubのWikiに記載されているので、参考にしてください。
Jetpack Composeとは
GoogleI/O 2019で発表された、AndroidのUIを宣言的に構築できるツールキットです。
宣言的UIとは何かについては、以下の記事が個人的に参考になりました。
EpoxyRecyclerViewをComposeに置き換える
ここからが本題です。
弊社では、xml・data-bindingで構成されている既存のUIをComposeに置き換える対応を行っています。
既存のUIでリスト表示やViewを構築する際に、data-bindingでのEpoxyRecyclerViewを使用しています。
ComposeにもLazyRowやLazyColumnといった、多数のアイテムを表示するコンポーネントが提供されているので、簡単なリスト表示であれば、そちらを使用しますが、EpoxyRecyclerViewで実装しているUIは結構複雑なUIだったので、LazyRowやLazyColumnに置き換えるのに時間がかかりました。
そこでちょうど、Epoxyの5.0.0からComposeに対応した(安定版) ので、そちらを使用してEpoxyRecyclerViewの一部のUIをComposeで実装してみようと思いました。
AndroidViewのようにxmlやdata-bindingと併用してComposeをかけるので、とても便利で実装しやすかったです。
その書き方について簡単に紹介します。
今回は、data-bindingも使用していることとComposeをAndroidプロジェクトに導入していることを前提で書きたいと思います。
導入
build.gradle
にcom.airbnb.android:epoxy-compose
を書いて、プロジェクトに読み込みさせます。
marven repository
にバージョンが記載されているので、バージョンを調べて入れてください。
apply plugin: "kotlin-kapt"
android {
// 中略
buildFeatures {
dataBinding true // data-binding有効
compose true // compose有効
}
composeOptions {
kotlinCompilerExtensionVersion = "1.3.2"
}
}
kapt {
correctErrorTypes = true
}
dependencies {
// 中略
// compose
def jetpack_compose_version = "2023.01.00"
implementation platform("androidx.compose:compose-bom:$jetpack_compose_version")
implementation "androidx.compose.ui:ui"
implementation "androidx.compose.material:material"
// epoxy
def epoxy_version = "5.1.1"
implementation "com.airbnb.android:epoxy:$epoxy_version"
implementation "com.airbnb.android:epoxy-databinding:$epoxy_version" // epoxy with data-binding
implementation "com.airbnb.android:epoxy-compose:$epoxy_version" // epoxy with compose
kapt "com.airbnb.android:epoxy-processor:$epoxy_version"
}
レイアウト
EpoxyのComposeは、EpoxyRecyclerView
上で動作するので、レイアウトファイルが必要です。
(ここまでは、普通にEpoxyRecyclerViewを使用するのと一緒です。)
<!-- data-bindingなので、layoutタグで囲む -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<com.airbnb.epoxy.EpoxyRecyclerView
android:id="@+id/epoxy_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</layout>
Activity・Fragmentにbindingを紐付ける
data-bindingを使用しているので、一度ビルドすると、ActivityMainBinding
のようなViewDataBinding
を継承したクラスが生成されると思います。これをActivity・Fragmentと紐付けます。
class MainActivity: AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// bindingにレイアウトを読み込ませる
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
}
}
EpoxyRecyclerView内にJetpackComposeをおく
withModelsメソッドのラムダ内で、composableInteropメソッドを呼び出します。
そのラムダ内でコンポーネントを呼び出すと、Composeで作成されたUIがEpoxyRecyclerView常に表示されます。
class MainActivity: AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// bindingにレイアウトを読み込ませる
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
// EpoxyRecyclerViewのBind
binding.epoxyRecyclerView.withModels {
// Composeのコンポーネントを呼び出す
composableInterop("hello_text") {
HelloText("Hello, World!")
}
}
}
@Composable
private fun HelloText(text: String) {
Text(
text = text,
color = Color.Red,
fontSize = 32.sp,
fontWeight = FontWeight.Bold
)
}
}
実行
実際に実行すると以下のようになります!
最後に
data-bindingとComposeを併用する場合でも、難しい設定やコードを書かずに実装をすることができます。
UIをComposeで書く分、アニメーションや状態管理はしやすいかなと個人的に思います。
Epoxyを使用しているプロジェクトにComposeを導入することを考えている場合は、併用するということも視野に入れてみるといいと思います!
その際は、この記事を参考にしていただけると幸いです。🙇
サンプルコード
今回のサンプルコードをGithubにあげているので、コードを見たい方はこちら。
公式もサンプルコードを提供しているので、そちらも参考にしてみてください!
Discussion