美文网首页Litho
Litho学习--列表的实现-2

Litho学习--列表的实现-2

作者: 言者无知_n4c | 来源:发表于2018-05-21 00:23 被阅读67次

接着上篇 简单的列表-1,这一篇主要讲解如何在列表的顶部添加一个水平滚动的列表,充分利用 Litho 和 Section API 的可组合性。

简单的列表-1 中 ListSectionSpec 描述了一个包含有 32 个子 SingleComponentSection 的 GroupSection ,每个 SingleComponentSection 负责渲染一个 ListItem Component,每个 Component 的内容只有显示的数字发生了变化。

这篇中将利用 Litho 中的另外一个核心 Section :DataDiffSection 来渲染列表, 我们把 ListSectionSpec 中的 SingleComponentSection 替换成 DataDiffSection 。

本篇中的例子把上篇例子中的 ListItemSpec 变成了 ListItem2Spec , ListSectionSpec 变成了 ListSection2Spec, ListSectionSpec 与 ListItemSpec 对应,ListSection2Spec 与 ListItem2Spec 对应。

1. 重构列表

首先,把 ListItemSpec 中的三个属性抽取为一个数据模型:

public class DataModel {
    public String title;
    public String subtitle;
    public int color;
}

把 ListItemSpec 按照如下修改:

@LayoutSpec
public class ListItem2Spec {

    @OnCreateLayout
    static Component onCreateLayout(
            ComponentContext c,
            @Prop DataModel dataModel) {

        return Column.create(c)
                .paddingDip(ALL, 16)
                .backgroundColor(dataModel.color)
                .child(
                        Text.create(c)
                                .text(dataModel.title)
                                .textSizeSp(40))
                .child(
                        Text.create(c)
                                .text(dataModel.subtitle)
                                .textSizeSp(20))
                .build();
    }
}

在 ListSection2Spec 中添加生成列表的方法,这里使用静态方法模拟,实际场景应该是拉取数据:

 private static List<DataModel> generateData(int count) {
        final List<DataModel> data = new ArrayList<>(count);
        for (int i = 0; i < count; i++) {
            DataModel model = new DataModel();
            model.color = (i % 2 == 0 ? Color.WHITE : Color.LTGRAY);
            model.title = i + ". Hello, world!";
            model.subtitle = "Litho tutorial";
            data.add(model);
         }
        return data;
    }

再写一个方法,接收 DataModel 参数,创建一个 ListItem2 。

@OnEvent(RenderEvent.class)
    static RenderInfo onRender(final SectionContext c, @FromEvent DataModel model,@FromEvent int index) {
        return ComponentRenderInfo.create()
                .component(
                        ListItem2.create(c)
                                .dataModel(model)
                                .build())
                .build();
    }

接下来把两个方法结合在一起,修改 onCreateChildren 方法:

@OnCreateChildren
    static Children onCreateChildren(final SectionContext c) {
        return Children.create()
                .child(
                        DataDiffSection.<DataModel>create(c)
                                .data(generateData(32))
                                .renderEventHandler(ListSection2.onRender(c)))
                .build();
    }

那么 @OnEvent 是什么东西?ListSection2.onRender(c) 又是怎么来的?
下面简单解释一下:

  • 当一个列表条目需要被渲染的时候,DataDiffSection 会产生一个 RenderEvent。
  • 创建 DataDiffSection 的时候,我们传入自定义的 RenderEventHandler ,ListSection2.onRender(c)。
  • 这个自定义的 EventHandler 在接收到 RenderEvent 的时候,会调用在 ListSection2Spec 中定义的 onRender 方法。
  • 所有的 EventHandler 是由 @OnEvent 注解标注的代码生成的。

运行APP,效果如下:


简单列表实现-2

2. 添加水平滚动列表

还记得我们是如何用RecyclerCollectionComponent来创建列表的么?应为RecyclerCollectionComponent自身也是一个Component,所以我们可以在Section里再创建一个列表,轻松实现嵌套列表。在一个垂直的列表中再嵌套一个垂直的列表是没有意义的,比较常见的是在垂直列表中嵌入一个水平列表。接下来我们就要这么做。

更新 onCreateChildren()中的代码,在DataDiffSection前面加一个SingleComponentSection:

    @OnCreateChildren
    static Children onCreateChildren(final SectionContext c) {
        return Children.create()
            .child(
                SingleComponentSection.create(c)
                .component(
                    RecyclerCollectionComponent.create(c)
                        .disablePTR(true)
                        .recyclerConfiguration(new ListRecyclerConfiguration(LinearLayoutManager.HORIZONTAL, /*reverse layout*/ false, SNAP_TO_CENTER))
                        .section(
                            DataDiffSection.<DataModel>create(c)
                                .data(generateData(32))
                                .renderEventHandler(ListSection2.onRender(c))
                        )
                        .canMeasureRecycler(true)
                )
                .build()
            )
            .child(
                DataDiffSection.<DataModel>create(c)
                    .data(generateData(32))
                    .renderEventHandler(ListSection2.onRender(c))
            )
            .build();
    }

这里我们看到 RecyclerCollectionComponent 的几个新 props:

  • recyclerConfiguration 接收一个配置对象用于设置组件的布局以及RecyclerCollectionComponent的对齐方式。
  • canMeasureRecycler对于没有固定高度的水平 RecyclerCollectionComponent 来说须设置成true。RecyclerCollectionComponent会测量第一个孩子的高度并将此高度作为整个水平列表的高度。

运行APP,应该会看到如下画面:

简单列表-2-带水平列表

相关文章

网友评论

    本文标题:Litho学习--列表的实现-2

    本文链接:https://www.haomeiwen.com/subject/yvdxjftx.html