Epoxy - 在RecyclerView中构建复杂界面 - 5

965 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

EpoxyRecyclerView

Epoxy提供了EpoxyRecyclerView类来启用Epoxy和RecyclerView之间的合成. 这个类的目的是: 通过应用通用的默认配置来减少设置RecyclerView的模板代码. 此外, 也进行了一些性能优化.

开始之前, 先使用EpoxyRecyclerView取代RecyclerView, 接下来查看更多的细节.

该类的改进有:

  1. 单一视图池在所有的EpoxyRecyclerView实例之间自动共享.
  2. 默认设置自动添加了布局管理器.
  3. 如果视图的大小是MATCH_PARENT, 那么启用了固定大小.
  4. 如果使用了GridLayoutManager, 那么EpoxyController会自动同步automatically syncspan数目.
  5. 辅助方法在无需创建EpoxyController类的情况下设置 Model.
  6. 设置EpoxyController并构建 Model 只需一步.
  7. 支持自动item spacing
  8. Carousel中提供了用作嵌套Recyclerview的默认值.
  9. setClipToPadding(boolean)默认设置了false, 因为该行为通常用于滚动列表.

共享视图池

为了最大化视图回收, 在相同的Activity中, 所有的EpoxyRecyclerView实例共享相同的视图池.

而且, 在视图池中并没有限制视图的数目. RecyclerView默认限制视图池为每种类型5个视图, 但对于嵌套RecyclerView或者每行超过5项的网格, 限制并不生效, 并且新的视图不断地创建. 我们通过将池大小设置为一次需要的视图数量所需的大小来防止这种情况.

默认布局管理器

正常情况下需要手动地给RecyclerView添加LayoutManager. 该类基于布局参数设置默认添加LayoutManager.

默认情况下使用LinearLayoutManager, 并且基于布局参数为滚动方向选择合理的默认设置.

如果RecyclerView设置了match_parent, 那么滚动方向设置了vertical, 并且setHasFixedSize设置为true.

如果高度设置了wrap_content, 那么滚动方向设置为horizontal, 并且setClipToPadding设置为false.

可以继承EpoxyRecyclerView并覆盖createLayoutManager方法建立自己的默认设置.

添加Controller很容易

正常情况下需要像这样实例化RecyclerView和EpoxyController:

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

有了EpoxyRecyclerView, 只需要:

epoxyRecyclerView.setControllerAndBuildModels(new MyEpoxyController());

如果你喜欢的话, 可以像这样:

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

可以稍后通过调用epoxyRecyclerView.requestModelBuild()触发 Model 构建.

在没有Controller的情况下构建 Model.

有时候不需要创建完整EpoxyController类的开销.

可以直接创建 Model 列表, 并且在 RecyclerView 上直接设置:

epoxyRecyclerView.setModels(modelsList);

或者可以通过回调构建 Model:

Kotlin代码:

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

这充分利用了Epoxy产生的扩展函数

Java代码:

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

也可以在 Activity/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);
  }
}

稍后可以通过调用epoxyRecyclerView.requestModelBuild()触发 Model 构建.

Item Spacing

调用EpoxyRecyclerView#setItemSpacingPx使得Epoxy自动在 RecyclerView 的所有项之间自动插入spacing. 这在LinearLayoutManagerGridLayoutManager的横竖项滚动 Model 中都生效, 即使是反向布局也是如此.

最佳实践是通过ItemDecorator来完成; 这仅仅是删除了手动设置的模板代码.

这只在项之间添加spacing. 如果你想在RecyclerView的外边界添加spacing, 则需要按需要在RecyclerView上设置padding. EpoxyRecyclerView默认禁用了setClipToPadding, 所以项会通过 padding 展示spacing.

调用setItemSpacingPx(0)禁用了自动spacing. 也有通过DP或者资源进行设置的等价方法.

网格集成

如果在用GridLayoutManager, 正常情况下必须让Epoxy知道网格span数目并且设置网格 span 数目查找(详情请看). 有了EpoxyRecyclerView, span 大小在给RecyclerView添加GridLayoutManager的时候会自动同步.