Litho学习之--列表的实现-1

这篇文章主要讲解一个简单列表的实现,包括如何自定义列表中的每个条目, 利用 RecyclerCollectionComponent 组件以及 Sections 库来创建列表,如何自定义每个组件的属性。

第一个自定义组件

首先我们先来定义列表中的条目,每个条目包含一个主标题和副标题,Litho 的预定义组件中并没有这样的组件,事实上也不应该有这样的组件,需要我们自定义组件,相当于在 Android 系统中 LinearLayout 中的垂直方向摆放两个 TextView 。 Litho 中,编写 Spec 类来声明组件的布局,也就是编写各种不同组件的组合,在 Spec 类上添加 @LayoutSpec 注解,编写一个用 @OnCreateLayout 注解的方法返回需要显示的组件,实际上用到的类是去掉 Spec 后缀的 Component 类,框架会生成代码中真正用到的 Component 类,这里我们的自定义组件叫做 ListItem ,相应地,我们要编写 ListItemSpec 类:

@LayoutSpec
public class ListItemSpec {

  @OnCreateLayout
  static Component onCreateLayout(ComponentContext c) {

    return Column.create(c)
        .paddingDip(ALL, 16)
        .backgroundColor(Color.WHITE)
        .child(
            Text.create(c)
                .text("Hello world")
                .textSizeSp(40))
        .child(
            Text.create(c)
                .text("Litho tutorial")
                .textSizeSp(20))
        .build();
  }

}

解释:

这里的 Text 就是 Hello World 里面见到的 Litho 中的核心组件,这个例子中,我们把 Text 组件作为 Column 的子组件传入,这里的 Column 相当于 Android 中垂直方向的 LinearLayout ,里面设置了 padding 和 backbroundColor 两个属性。

那么如何使用我们刚刚编写的这个组件?

final Component component = ListItem.create(context).build();

注意:这里我们用的是 ListItem,而不是 ListItemSpec。

那么 ListItem 是怎么来的? create() 和 build() 方法在哪里定义的?
在 Hello World 中我们在 gradle 文件中添加入了有关注解处理器的依赖, Litho 的注解处理器会扫描代码,查找 Spec 类,并生成去掉后缀 Spec 的组件类,同时自动填充一些必要的方法。

Litho 还可以实现类似于 LinearLayout 中的 weight 和 FrameLayout 的效果,请参考 Layout

运行APP,效果如下:

First Custom Component

创建列表

这一节我们要使用到 Litho 中的 RecyclerCollectionComponent 组件以及 Sections 库来创建列表。
RecyclerCollectionComponent 用于创建 Litho 滚动的单元,隐藏了直接使用 Android 中 RecyclerView 和 Adapter 交互的复杂性。
Sections API 可以把列表中的条目放到 Section 中,写 GroupSectionSpec 类来声明每个 Section 要渲染的内容和使用的数据。
这里我们要自定义的 Section 叫做 ListSection, 因此需要声明 ListSectionSpec 类,在类上添加 @GroupSectionSpec 注解,定义 onCreateChildren 方法,返回需要渲染的子 Section 们,这里每个子 Section 显示一个 ListItem 组件。

@GroupSectionSpec
public class ListSectionSpec {

  @OnCreateChildren
  static Children onCreateChildren(final SectionContext c) {
    Children.Builder builder = Children.create();

    for (int i = 0; i < 32; i++) {
      builder.child(
          SingleComponentSection.create(c)
              .key(String.valueOf(i))
              .component(ListItem.create(c).build()));
    }
    return builder.build();
  }
}

解释:
SingleComponentSection 是 Litho Section API 提供中的一个核心 Section,定义在 com.facebook.litho.sections.widget 这个包中,只不过这个 Section 负责渲染一个单一的 Component 。ListSectionSpec 描述了一个包含有 32 个子 Section 的 Section ,这 32 个子 Section 中,每个 Section 负责渲染一个 ListItem 组件。
这里定义的是 Section ,并没有定义 Component,那么如何把 Section 显示在屏幕上?
把 Activity 中组件的定义改成下面的代码:

final Component component =
    RecyclerCollectionComponent.create(context)
        .disablePTR(true)
        .section(ListSection.create(new SectionContext(context)).build())
        .build();

注意:这里使用的是 ListSection ,而不是 ListSectionSpec 。

解释:

这里我们用 RecyclerCollectionComponent 这个组件,把刚刚定义的Section 显示在屏幕上。 RecyclerCollectionComponent 接收一个 Section 作为属性,会渲染一个 RecyclerView 显示 Section中的内容。它来管理数据刷新的操作,这里不使用下拉刷新功能,所以 通过设置 .disablePTR(true) 把这个功能关掉。

运行代码,效果如下:

列表实现1

定义组件的属性

上面的列表中,我们所有的列表项都显示重复的内容,现在我们想要列表中的内容是变化的。
这里引入 Litho 中属性的概念,也就是 Prop 。Component 的属性就是 Component Spec 类(这个类是我们编写用于生成对应的 Component 类的)中方法的参数,这些参数上带有 @Prop 注解。

把 ListItemSpec 进行如下修改:

@OnCreateLayout
static Component onCreateLayout(
    ComponentContext c,
    @Prop int color,
    @Prop String title,
    @Prop String subtitle) {

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

解释:
这里我们添加了三个属性,color,title,subtitle 。这里的 backgroundColor 以及 Text 组件的 文本内容不再是硬编码的形式,而是根据 onCreateLayout 方法中的参数给出。

Litho 的注解处理器会根据 @Prop 注解,为注解的参数生成相应的构造器方法,例如这里参数名称是 color,就会为 ListItem 生成 color(int) 方法,相应地,这里还会生成另外两个构造器方法,title(String) ,subtitle(String) 。在创建 ListItem 组件的时候,就需要在构造器方法中,对属性进行赋值。

修改 ListSection 中的方法:

@OnCreateChildren
static Children onCreateChildren(final SectionContext c) {
  Children.Builder builder = Children.create();

  for (int i = 0; i < 32; i++) {
    builder.child(
        SingleComponentSection.create(c)
            .key(String.valueOf(i))
            .component(ListItem.create(c)
               .color(i % 2 == 0 ? Color.WHITE : Color.LTGRAY)
               .title(i + ". Hello, world!")
               .subtitle("Litho tutorial")
               .build()));
  }
  return builder.build();
}

另外,属性上还可以有其他选项,例如:
@Prop(optional = true, resType = ResType.DIMEN_OFFSET) int shadowRadius,

注解处理器还会生成一些对应的方法 :shadowRadiusPx, shadowRadiusDip, shadowRadiusSp 以及 shadowRadiusRes。

注意:

  1. Prop 可以被 Spec 中不同的生命周期方法访问,只需要在相应的方法参数上添加这个 Prop ,Litho 保证每个方法访问到的属性值是一致的,但是要保证同一个Prop 在不同方法中的声明完全一致,比如 方法1 中 使用 @Prop(optional = true) String prop1,那么 方法2 中也要采用 @Prop(optional = true) String prop1, 否则注解处理器会报错。
  2. 另外对于 optional = true 的属性,在组件创建时可不传入该属性的值,如果未添加此项设置,则会在运行时报如下错误:下面是我把上面代码中的 subtitle一样注释掉报的错:
    java.lang.IllegalStateException: The following props are not marked as optional and were not supplied: [subtitle]
    有关属性的问题,请参考 Props

运行APP,会看到如下效果:


列表实现-带属性
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,576评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,515评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,017评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,626评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,625评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,255评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,825评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,729评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,271评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,363评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,498评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,183评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,867评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,338评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,458评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,906评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,507评论 2 359

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,697评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,848评论 6 342
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,435评论 1 92
  • 凌寒夜冷风, 蹒跚雨中行, 繁逝悲由空寂寥。 唯犬吠知更独行! 徒步到凉晨, 荒鸡难鸣。 应化流风水断冰, 世道怎...
    夏墨凌语阅读 172评论 0 5
  • 1、15年底以前,我抵抗低落情绪的时候使用最多的方法之一就是跑步。 2、不幸的是,左膝关节外侧长年积累发生疼痛,5...
    五彩冰峰阅读 196评论 0 0