Skip to content

EpoxyRecyclerView

Eli Hart edited this page Oct 3, 2017 · 14 revisions

Will be released in 2.6.0 as a Beta component. Please leave feedback by opening an issue!

Epoxy provides the EpoxyRecyclerView class to enable easy integration between Epoxy and RecyclerView. The goal of this class is to reduce boilerplate in setting up a RecyclerView by applying common defaults. Additionally, several performance optimizations are made.

To get started, simply replace your RecyclerView usages with EpoxyRecyclerView, and read below for more details.

Improvements in this class are:

  1. A single view pool is automatically shared between all EpoxyRecyclerView instances.

  2. A layout manager is automatically added with sane defaults.

  3. Fixed size is enabled if this view's size is MATCH_PARENT

  4. If a GridLayoutManager is used this will automatically sync the span count with the EpoxyController.

  5. Helper methods to set models without needing to create a EpoxyController class.

  6. Set an EpoxyController and build models in one step

  7. Support for automatic item spacing

  8. Defaults for usage as a nested recyclerview are provided in Carousel.

  9. Kotlin Extensions

  10. setClipToPadding(boolean) is set to false by default since that behavior is commonly desired in a scrolling list

Shared View Pool

To maximize view recycling we share the same view pool across all EpoxyRecyclerView instances in the same Activity.

Also, we do not limit the number of views in the view pool. RecyclerView by default limits the pool to 5 views of each type, but this often does not work for nested RecyclerViews or grids that show more than 5 items in a row, and new views will constantly be created. We prevent this by making the pool size as large as needed for the number of views you need at once.

Default Layout Manager

Normally you have to manually add a LayoutManager to your RecyclerView. This class automatically adds one based on layout param settings.

By default a LinearLayoutManager is used, and a reasonable default is chosen for scrolling direction based on layout params.

If the RecyclerView is set to match_parent size then the scrolling orientation is set to vertical and setHasFixedSize is set to true.

If the height is set to wrap_content then the scrolling orientation is set to horizontal, and setClipToPadding is set to false for carousel usage.

You can subclass EpoxyRecyclerView and override createLayoutManager to establish your own default.

Easily Add Controllers

Normally you need to initialize a RecyclerView and EpoxyController like this

controller = new MyEpoxyController();
recycler.setAdapter(controller.getAdapter());
controller.requestModelBuild();

With EpoxyRecyclerView you can simply do

epoxyRecyclerView.setControllerAndBuildModels(new MyEpoxyController());

Or if you prefer

controller = new MyEpoxyController();
recycler.setController(controller);
controller.requestModelBuild(); // Delay building models until a later time

You can later trigger a model build by calling epoxyRecyclerView.requestModelBuild()

Build Models Without a Controller

Sometimes you may not need the overhead of creating a whole EpoxyController class.

You may instead directly create a list of models and set them on the recycler view

epoxyRecyclerView.setModels(modelsList);

Or you can build models with a callback

epoxyRecyclerView.buildModelsWith((controller) -> {
  new HeaderModel_()
     .id("header")
     .text("hello world)
     .addTo(controller);
});

You could also implement the callback in your activity or fragment.

class MyActivity extends Activity implements ModelBuilderCallback {
   
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    epoxyRecyclerView.buildModelsWith(this);
    ...
  }

  @Override
  public void buildModels(EpoxyController controller) {
    new HeaderViewModel_()
        .id("header")
        .title("hello world")
        .addTo(controller);
  }
}

You can later trigger a model build by calling epoxyRecyclerView.requestModelBuild()

Item Spacing

Call EpoxyRecyclerView#setItemSpacingPx to have Epoxy automatically insert spacing between all items in the RecyclerView. This works with LinearLayoutManager and GridLayoutManager in both horizontal and vertical scroll models, as well as with reversed layouts.

This is done via an ItemDecorator as is common practice; this just removes the boilerplate of setting it up yourself.

This only adds spacing between items. If you would like spacing on the outside edges of the RecyclerView you can set padding on the RecyclerView as needed. EpoxyRecyclerView has setClipToPadding disabled by default so items will be shown through padding.

Call setItemSpacingPx with 0 to disable automatic item spacing. There are also equivalent methods for setting spacing in DP or via a resource.

Kotlin Extensions

With a Kotlin extension function we can further simplify the model building mentioned above to just

epoxyRecyclerView.withModels {
        header {
            id("header")
            title("hello world")
        }
    }

This uses the function

/** Easily add models to an EpoxyRecyclerView, the same way you would in a buildModels method of EpoxyController. */
fun EpoxyRecyclerView.withModels(buildModelsCallback: EpoxyController.() -> Unit) {
    setControllerAndBuildModels(object : EpoxyController() {
        override fun buildModels() {
            buildModelsCallback()
        }
    })
}

to let you build models off a RecyclerView as easily as you would in an EpoxyController. This leverages Epoxy's generated extension functions

Epoxy does not yet package Kotlin extensions, but you can add this to your own project if needed.

Grid Integration

If you are using a GridLayoutManager you normally have to let Epoxy know what the grid span count is and set up the grid span size look up (as detailed here). With EpoxyRecyclerView this span size synchronization is done automatically when you add a GridLayoutManager to the RecyclerView.