Epoxy is an Android library for building complex screens in a RecyclerView. Models are automatically generated from custom views or databinding layouts via annotation processing. These models are then used in an EpoxyController to declare what items to show in the RecyclerView.
This abstracts the boilerplate of view holders, diffing items and binding payload changes, item types, item ids, span counts, and more, in order to simplify building screens with multiple view types. Additionally, Epoxy adds support for saving view state and automatic diffing of item changes.
We developed Epoxy at Airbnb to simplify the process of working with RecyclerViews, and to add the missing functionality we needed. We now use Epoxy for most of the main screens in our app and it has improved our developer experience greatly.
Gradle is the only supported build configuration, so just add the dependency to your project build.gradle
file:
dependencies {
implementation "com.airbnb.android:epoxy:$epoxyVersion"
// Add the annotation processor if you are using Epoxy's annotations (recommended)
annotationProcessor "com.airbnb.android:epoxy-processor:$epoxyVersion"
}
Replace the variable $epoxyVersion
with the latest version :
See the releases page for up to date release versions and details
If you are using Kotlin you should also add
apply plugin: 'kotlin-kapt'
kapt {
correctErrorTypes = true
}
so that AutoModel
annotations work properly. More information here
Also, make sure to use kapt
instead of annotationProcessor
in your dependencies in the build.gradle
file.
If you are using layout resources in Epoxy annotations then for library projects add Butterknife's gradle plugin to your buildscript
.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.jakewharton:butterknife-gradle-plugin:10.1.0'
}
}
and then apply it in your module:
apply plugin: 'com.android.library'
apply plugin: 'com.jakewharton.butterknife'
Now make sure you use R2 instead of R inside all Epoxy annotations.
@ModelView(defaultLayout = R2.layout.view_holder_header)
public class HeaderView extends LinearLayout {
....
}
This is not necessary if you don't use resources as annotation parameters, such as with custom view models.
There are two main components of Epoxy:
- The
EpoxyModel
s that describe how your views should be displayed in the RecyclerView. - The
EpoxyController
where the models are used to describe what items to show and with what data.
Epoxy generates models for you based on your view or layout. Generated model classes are suffixed with an underscore (_
) are used directly in your EpoxyController classes.
Add the @ModelView
annotation on a view class. Then, add a "prop" annotation on each setter method to mark it as a property for the model.
@ModelView(autoLayout = Size.MATCH_WIDTH_WRAP_HEIGHT)
public class HeaderView extends LinearLayout {
... // Initialization omitted
@TextProp
public void setTitle(CharSequence text) {
titleView.setText(text);
}
}
A HeaderViewModel_
is then generated in the same package.
If you use Android DataBinding you can simply set up your xml layouts like normal:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="title" type="String" />
</data>
<TextView
android:layout_width="120dp"
android:layout_height="40dp"
android:text="@{title}" />
</layout>
Then, create an interface or class in any package and add an EpoxyDataBindingLayouts
annotation to declare your databinding layouts.
package com.airbnb.epoxy.sample;
import com.airbnb.epoxy.EpoxyDataBindingLayouts;
@EpoxyDataBindingLayouts({R.layout.header_view, ... // other layouts })
interface EpoxyConfig {}
From this layout name Epoxy generates a HeaderViewBindingModel_
.
If you use xml layouts without databinding you can create a model class to do the binding.
< 8000 div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="@EpoxyModelClass(layout = R.layout.header_view) public abstract class HeaderModel extends EpoxyModelWithHolder<Holder> { @EpoxyAttribute String title; @Override public void bind(Holder holder) { holder.header.setText(title); } static class Holder extends BaseEpoxyHolder { @BindView(R.id.text) TextView header; } }">@EpoxyModelClass(layout = R.layout.header_view) public abstract class HeaderModel extends EpoxyModelWithHolder<Holder> { @EpoxyAttribute String title; @Override public void bind(Holder holder) { holder.header.setText(title); } static class Holder extends BaseEpoxyHolder { @BindView(R.id.text) TextView header; } }