LoginSignup
10
9

More than 3 years have passed since last update.

Epoxy入門:複雑な画面をRecyclerViewで楽に作る

Last updated at Posted at 2019-05-01

Epoxyとは

EpoxyはRecyclerViewで複雑な画面を構成するためのAndroidライブラリ。
ScrollViewで縦に長い画面をRecyclerViewで楽に管理するのが目的

どうやって使う?

主に使うのはEpoxyModelEpoxyController
モデルはCustomView、xmlレイアウト(DataBinding)から自動生成される。
そのモデルをコントローラーで並べて宣言するだけ。

今回はKotlin + DataBindingを使う方法を説明する。

インストール

公式に従ってapp/build.gradleにライブラリを追加
https://github.com/airbnb/epoxy#installation

app/build.gradle
dependencies {
    // 以下3行のEpoxyライブラリを追加
    implementation 'com.airbnb.android:epoxy:3.4.2'
    kapt 'com.airbnb.android:epoxy-processor:3.4.2' // Kotlinはkaptを使用
    implementation 'com.airbnb.android:epoxy-databinding:3.4.2'
    ...
  • 2019/04/30時点では3.4.2が最新
  • epoxy-processorはJavaではannotationProcessor、Kotlinではkaptを使うべし
  • epoxy-databinding はDataBindingを連携させるなら追加

EpoxyModelの作り方

今回はDataBindingのみ記載する。

DataBindingの場合、レイアウトxmlから自動でModelを作成するよう記述する。

やる事は以下
- レイアウトxmlをDataBindingで作成
- package-info.java を作成
- 一回ビルド

やることを順に説明する

レイアウトxmlをDataBindingで作成

表示するViewをいつもどおりxmlで作成する。
DataBinding化することを忘れずに。

今回はheader_view.xmlbody_view.xmlfooter_view.xmlを作成した。

package-info.java を作成

package-info.java を以下の場所に作る

スクリーンショット 2019-05-01 12.55.23.png

パス
プロジェクト名/app/src/main/java/package-info.java

内容

package-info.java
@EpoxyDataBindingLayouts({R.layout.header_view, R.layout.body_view, R.layout.footer_view})
package com.ikemura.android_kotlin_lab;

import com.airbnb.epoxy.EpoxyDataBindingLayouts;

@EpoxyDataBindingLayoutsにレイアウトxmlを指定すると、Modelが自動生成される。

このファイルを作る時、自分で入力して作ろうとするとIDEが認識せずおかしくなった。
本家からコピペで作ったらやっと認識した。
一体なんだったんだろうか

一回ビルド

レイアウトxmlとpackage-info.javaを作成したら一度ビルドしておく。
このビルドでDataBindingファイルとEpoxyModelが自動生成される。

自動生成されたEpoxyModelは以下
- HeaderViewBindingModel_
- BodyViewBindingModel_
- FooterViewBindingModel_

みて分かるとおり、〜BindingModel_ という命名でレイアウトからModelが作られる。

EpoxyControllerの作り方

2パターンある

引数がない時

EpoxyControllerを継承したクラスを作る。
静的画面を作る際に使う

class MainController : EpoxyController() {
    override fun buildModels() {
      ...
    }

引数があるとき

引数が1つの場合は
TypedEpoxyControllerを継承して、buildModelsメソッドで引数を受け取る。

class MainController : TypedEpoxyController<DummyContent.DummyItem>() {
    override fun buildModels(data: DummyContent.DummyItem?) {

    }

引数がの数によって継承するクラスを使い分けるようだ。
2つの場合は Typed2EpoxyController
3つの場合は Typed3EpoxyController
4つの場合は Typed4EpoxyController

と4つまでの引数に対応している。

作り方

まずViewを表示するだけの一番シンプルなコード

class MainController : EpoxyController() {
    override fun buildModels() {
        headerView {
            id("header")
        }
        bodyView {
            id("body")
        }
        footerView {
            id("footer")
        }

EpoxyControllerを継承し、buildModels内に表示したい順にEpoxyModelを宣言する。
これだけで画面表示は完成している、Epoxyすごい

初見だと上記のControllerを見ても「???」となると思うので軽く説明。

id()

id()はEpoxyが内部でModelを管理するために必要らしい。
渡された値(今回は文字列)を内部でハッシュコード化して、Modelを識別してるようだ。
ちなみにこのidを指定しないとIllegalEpoxyUsageというエラーが投げられ、「モデルにidを指定する必要がある」と怒られる。

headerView {}

headerView {}はなにかというと、Epoxyによって自動生成された拡張関数である。

EpoxyModelKotlinExtensions.kt
が自動生成されており、中身はこんな感じ

inline fun EpoxyController.headerView(modelInitializer: HeaderViewBindingModelBuilder.() -> Unit) {
    HeaderViewBindingModel_().apply  {
        modelInitializer()
    }
    .addTo(this)
}

拡張関数内では
HeaderViewBindingModel_に引数で渡された関数を実行し(modelInitializer()のとこ)
addTo(this)でモデル(HeaderViewBindingModel)にEpoxyControllerを紐づけている。

画面に表示

表示を全てEpoxyに任せるなら、レイアウトxmlにはRecyclerViewだけ設置するだけでよい
そのRcyclerViewのAdapterに、EpoxyControllerを渡すだけ

表示する画面のレイアウトxml

RecyclerViewだけ設置するだけでOK

epoxy_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recycler_view"
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="16dp"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    tools:context=".epoxy.EpoxyFragment"
    />

RecyclerViewにEpoxyControllerを渡す

Activity or Fragment内でEpoxyControllerを渡す

    private fun setupEpoxyController() {
        val controller = MyEpoxyController() // EpoxyControllerのインスタンス化
        recycler_view.adapter = controller.adapter  // adapterを渡す
        controller.requestModelBuild() // データを渡さない場合はrequestModelBuild、渡す場合はsetDataを使う
    }

コメントにも書いてあるが、
データを渡さない場合はrequestModelBuild、渡す場合はsetDataに表示するデータ等を渡す

スクショ
2019-05-01-23-43-43.png

2019-05-01-23-44-09.png

Epoxyの感想

初めはViewなのかModelなのかごっちゃになって混乱したが、作っていくと「あーなるほどね」と理解できた。
DataBindingの場合はViewModelのようなクラスが自動生成される、というイメージかな。
(〜BindingModel_ ←こんなクラス)
静的な画面でも縦に長くなる場合はEpoxyを使うと楽になるかも。

RecyclerViewと数十行のEpoxyContorollerだけで画面表示を制御できるのは強力だと思う。

ぜひ自分の担当するプロジェクトにも導入してみたい。

参考にしたページ

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9