Litho 使用具有不可变输入的单向数据流。 按照React建立的名称,Component 采用的输入称为 props。
定义和使用 props
给定 Component 的 props 是在spec方法中用 @Prop 注解的所有参数的联合。您可以在所有声明为 @Prop 参数的方法中访问 props 的值。
可以在多个生命周期方法中定义和访问相同的 prop 。注解处理器确保所有 spec 方法中使用一致的 prop 类型和一致的注解参数。
以下面的Component Spec 为例:
@MountSpec
class MyComponentSpec {
@OnPrepare
static void onPrepare(
ComponentContext c,
@Prop(optional = true) String prop1) {
...
}
@OnMount
static void onMount(
ComponentContext c,
SomeDrawable convertDrawable,
@Prop(optional = true) String prop1,
@Prop int prop2) {
if (prop1 != null) {
...
}
}
}
MyComponentSpec 定义了两个 props:一个名为 prop1 的 String prop 和一个名为 prop2 的 int prop。 prop1 是可选的,它需要在定义它的所有方法中标记,否则注解处理器将抛出异常。
当生命周期方法被调用时,@Prop 参数将保存在创建组件时(或其默认值)从父组件传递的值。
在 LayoutSpecs 和 MountSpecs 中定义和使用 props 的方式相同。
设置 props 的值
对于在 Spec 中定义的每个唯一 prop ,注解处理器会在组件生成器上创建一个构建器模式方法,该方法与 prop 具有相同的名称,并且把仅有的参数值设置该 prop 。
通过在生成的组件生成器上调用适当的方法来传递这些 props 的值:
MyComponent.create(c)
.prop1("My prop 1")
.prop2(256)
.build();
props 的默认值
可以不必为可选的 prop 设置值,prop 的值会根据其定义类型设置成 Java 默认值。通常需要为组件的 props 定义显式的默认值,而不是简单地依赖于 Java 的默认值。
通过 @PropDefault 注解把默认的 prop 值定义为 Spe c类中的静态成员。我们来定义上述 prop 的默认值:
@MountSpec
public class MyComponentSpec {
@PropDefault static final String prop1 = "mydefaultvalue";
@PropDefault static final int prop2 = -1;
...
}
通过设置 resType 和 resId ,Prop 默认值还支持来自 Resources 的默认值。我们来为 @PropDefault 注解的变量定义默认资源值:
@PropDefault(resType = ResType.DIMEN_SIZE, resId = R.dimen.default_spacing) static float prop3;
资源类型
在创建布局时,使用 Android 资源系统的值很常见,例如尺寸,颜色,字符串等。Litho 提供了简便方法,通过注解把 Android 资源中的值设为 prop 的值。
我们来看一个简单的例子: @LayoutSpec public class MyComponentSpec {
@OnCreateLayout
static Component onCreateLayout(
LayoutContext context,
@Prop CharSequence someString,
@Prop int someSize,
@Prop int someColor) {
...
}
}
在上面的示例中,MyComponent 希望使用 整型的颜色值(someColor),像素尺寸(someSize)和字符串(someString)作为 props 的值。通常情况下,您需要使用资源值来设置这些 props 的值:
Resources res = context.getResources();
MyComponent.create(c)
.someString(res.getString(R.string.my_string))
.someSize(res.getDimensionPixelSize(R.dimen.my_dimen))
.someColor(res.getColor(R.color.my_color))
该框架允许使用资源类型标注 props,以便方便快捷地在组件构建器中直接使用资源值。
@LayoutSpec
public class MyComponentSpec {
@OnCreateLayout
static Component onCreateLayout(
LayoutContext context,
@Prop(resType = ResType.STRING) CharSequence someString,
@Prop(resType = ResType.DIMEN_SIZE) int someSize,
@Prop(resType = ResType.COLOR) int someColor) {
...
}
}
通过以上更改,MyComponent的构建器将根据其资源类型为 prop 生成带有 Res,Attr ,Dip 以及 Px 的方法。所以可以像下面这样:
MyComponent.create(c)
.someStringRes(R.string.my_string)
.someSizePx(10)
.someSizeDip(10)
.someColorAttr(android.R.attr.textColorTertiary)
其他支持的资源类型为 ResType.STRING_ARRAY ,ResType.INT ,ResType.INT_ARRAY ,ResType.BOOL ,ResType.COLOR ,ResType.DIMEN_OFFSET ,ResType.FLOAT 和 ResType.DRAWABLE 。
可变参数
有时候,想要参数支持列表。不幸的是,这可能会有点痛苦,因为它需要开发人员创建一个列表,将所有项目添加到列表里,并将这些项目传递给组件创建。 varArg参数旨在使列表型参数更容易一些。
@LayoutSpec
public class MyComponentSpec {
@OnCreateLayout
static Component onCreateLayout(
LayoutContext context,
@Prop(varArg = "name") List<String> names) {
...
}
}
使用方法如下:
MyComponent.create(c)
.name("One")
.name("Two")
.name("Three")
从版本0.6.2开始,这也适用于带有resType的 prop。例如,给定一个像这样的组件:
@LayoutSpec
public class MyComponent2Spec {
@OnCreateLayout
static Component onCreateLayout(
LayoutContext context,
@Prop(varArg = "sizes", resType = ResType.DIMEN_TEXT) List<Float> sizes) {
...
}
}
您可以通过调用构建器来添加多个 size:
MyComponent2.create(c)
.sizesPx(1f)
.sizesRes(resId)
.sizesAttr(attrResId)
.sizesDip(1f)
.sizesSp(1f)
不变性
组件的 prop 是只读的。组件的父组件在创建组件时传递 prop 的值,并且在组件的整个生命周期中 prop 的值都不能更改。如果必须更 prop 的值,父组件必须创建一个新的组件并传递 prop 的新值。 prop 对象应该是不可变的。由于异步布局,可以在多个线程上访问 props。props 的不变性确保组件层次结构中不会出现线程安全问题。