极光日报
首发于极光日报

在 Kotlin 中实现数据绑定框架中的 BindingAdapter 自定义属性

简评:介绍下在 Kotlin 中怎么实现数据绑定(data binding)框架的自定义属性。

使用 Android 的数据绑定框架的 @BindingAdapter 可以很方便的定义在布局文件中使用的自定义属性。一个常见的例子就是使用 Glide 或者 Picasso 来通过 URL 显示图片:

@BindingAdapter("bind:imageUrl")
public static void setImageUrl(ImageView view, String url) {
   Glide.with(view.getContext()).load(url).into(view);
}

布局文件:

<ImageView
    android:id="@+id/avatar"
    android:layout_width="@dimen/photo_size"
    android:layout_height="@dimen/photo_size"
    android:scaleType="centerCrop"
    app:imageUrl="@{user.avatarUrl}"/>

上面的例子是用 Java 实现,可以看到方法必须是 static 的。

但在 Kotlin 中呢?虽然 Kotlin 没有了 static 关键字,但 Kotlin 对方法定义的限制是要比 Java 少的,比如一个方法可以在类外被定义。

将 Kotlin 的方法定义在文件里,而不包含任何类:

@BindingAdapter("imageUrl")
fun setImageUrl(imageView: ImageView, url: String?) {
    Glide.with(imageView.context).load(url).into(imageView)
}

Extension functions

在 Kotlin 中我们还可以进一步简化这段代码,也就是通过 extension function 来扩展 ImageView(其实,Java static 方法和 Kotlin extension 方法,最后都是相同的字节码)。

@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
    Glide.with(context).load(url).into(this)
}

Properties

作者在自己的 Android 项目中经常定义的两个 BindingAdapter:

@BindingAdapter("visibleOrGone")
fun View.setVisibleOrGone(show: Boolean) {
    visibility = if (show) VISIBLE else GONE
}

@BindingAdapter("visible")
fun View.setVisible(show: Boolean) {
    visibility = if (show) VISIBLE else INVISIBLE
}

这样做主要是为了将 View 的可见性状态变为布尔值,方便使用,而不是原本的 Int 类型(VISIBLE, INVISIBLE 和 GONE)。

app:visibleOrGone="@{state.myBoolean}"

虽然,上面使用了 extension function,但在 Kotlin 中我们其实不需要去写 setter,我们可以用 properties,并在 BindingAdapter 前面加上 set 前缀来实现。

@set:BindingAdapter("visibleOrGone")
var View.visibleOrGone
    get() = visibility == VISIBLE
    set(value) {
        visibility = if (value) VISIBLE else GONE
    }

@set:BindingAdapter("visible")
var View.visible
    get() = visibility == VISIBLE
    set(value) {
        visibility = if (value) VISIBLE else INVISIBLE
    }

这样写在布局文件中的用法没有什么区别,同样是 app:visibleOrGone app:visible。在 Kotlin 代码中也可以很方便的设置:

if (!myView.visibleOrGone) {
    myOtherView.visible = true
}

总结

数据绑定框架中的自定义属性是非常有用的,可以简化很多逻辑。而通过 Kotlin 来实现的话可以有多种方式,可以根据实际情况来选择最适合的方式。

原文:Custom attributes using BindingAdapters in Kotlin

日报扩展阅读:

编辑于 2018-02-01

文章被以下专栏收录

    简介:每日导读(或翻译)三篇优质英文文章,内容 80% 涉及硅谷/编程/科技/,期待共同成长。