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

342 阅读2分钟

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

Kotlin Model 例子

Epoxy Model 可以用 Kotlin 很容易地写出来. 在 Kotlin 中推荐使用@ModelView或者ViewHolder途径 - 如果是自定义视图或者有更复杂的视图的话, 要使用@ModelView.

本页假设你已经理解了Epoxy. 这只会在Kotlin使用的不同之处添加额外的上下文.

这里是用Kotlin写 Model 的一些想法. 自己也可以适配这些想法并创建自己的模型. 要查看更多代码, 可以查看Kotlin Model 例子.

使用@ModelView

ModelView注解用在View上, 并从 View 上生成 Model. 这在Kotlin中非常简单, 但属性需要一些特殊处理.

@ModelView(autoLayout = ModelView.Size.MATCH_WIDTH_WRAP_HEIGHT)
class KotlinView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    @ModelProp
    fun setValue(value: Int) {
        // Do something here with value
    }

    // Or if you need to store data in properties there are two options

    // Can make it nullable like this and annotate the setter
    var myListener: View.OnClickListener? = null
        @CallbackProp set

    // Or use lateinit
    @TextProp lateinit var myText: CharSequence

    @AfterPropsSet
    fun useProps() {
        // This is optional, and is called after the annotated properties above are set.
        // This is useful for using several properties in one method to guarantee they are all set first.
    }
}

使用View Holder

这种更传统的风格使用了Epoxy view holder pattern. KotlinHolder用于缓存视图的查询, 并且使用属性委托来简化这个过程.

该注解允许生成子类, 该子类有equals/hashcode和一些其它的辅助. 也生成了扩展函数以使在EpoxyController中更容易使用 ViewHolder.

Holder代码用一个例子来提供, 可以拷贝到项目中并按需修改.

@EpoxyModelClass(layout = R.layout.view_holder_page_header)
abstract class SampleKotlinModelWithHolder : EpoxyModelWithHolder<Holder>() {

    @EpoxyAttribute lateinit var title: String
    @EpoxyAttribute lateinit var imageUrl: Uri

    override fun bind(holder: Holder) {
        holder.imageView.setImageURI(imageUrl)
        holder.titleView.text = title
    }

}

class Holder : KotlinHolder() {
    val titleView by bind<TextView>(R.id.title)
    val imageView by bind<ImageView>(R.id.image)
}

自定义Kotlin Model

官方未支持

这种方法使用了更加理想化的 Kotlin 方法, 并且不需要注解或者注解处理. 数据类用于生成 Epoxy 需要用来 diffing 的equals/hashcode方法. 通过属性代理View可以在 Model 中很容易地声明, 所以 View Holder也不需要了.

缺陷是视图会在每一次 Model 绑定到 View 时再次进行查询, 所以这并不很高效. 所以, 对于性能要求高的应用, 自定义 Kotlin Model 是不推荐的, 只是用于一个起点或者想法, 可能之后你想要进行适配.

如果你并不十分理解Epoxy, 或者不十分理解Kotlin, 以致不知道这个代码是干嘛的, 那么推荐你使用@ModelView或者ViewHolder方式.

基于KotlinModel例子, 你可以拷贝进项目然后适配.

缺点是你会丢失生成代码提供的一些功能(如用于EpoxyController的扩展功能)

data class SampleKotlinModel(
    val title: String,
    val imageUrl: Uri
) : KotlinModel(R.layout.view_holder_page_header) {

    val titleView by bind<TextView>(R.id.title)
    val imageView by bind<ImageView>(R.id.image)

    override fun bind() {
        titleView.text = title
        imageView.setImageURI(imageUrl)
    }
}