绑定适配器的做用就是,调用 UI
框架层合适的方法,给 view
属性进行赋值。android
好比,调用 setText()
方法给 TextView
的 text
属性赋值;调用 setOnClickListener()
方法,给 view
的 onClick
属性赋值。app
绑定适配器,可让你决定给 view
属性赋值调用哪一个方法,还可让你本身定制该方法的具体逻辑。框架
view
属性赋值当数据发生变化时,绑定类必须调用 view
的合适的 set()
方法,给 view
属性赋值。这时候有三种选择:一种是让 Data Binding
库本身决定调用哪一个方法;一种是明确指定调用哪一个方法;一种是本身定义一个方法。ui
Data Binding
库自动选择好比 view
有一个属性叫作 example
,Data Binding
库会试图去找一个 setExample(args)
的方法,这个方法接收的参数类型须要和绑定表达式的返回类型一致。注意,属性命名空间是不考虑的,寻找方法的惟一标准就是,方法名和参数类型。url
好比,对于表达式 android:text="@{user.name}"
,Data Binding
库会寻找该 view
的 setText(args)
方法,若是 user.name
的类型是 String
,则寻找 setText(String args)
方法;若是 user.name
的类型是 Int
,则寻找 setText(Int args)
方法。spa
即便一个 view
在 android
命名空间没有对应的属性,Data Binding
库依然能够正常工做。好比,DrawerLayout
并无 android:scrimColor
和 android:drawerListener
这些属性,却有 setScrimColor(int)
和 setDrawerListener(DrawerListener)
方法,这时咱们就可使用自定义命名空间的属性 app:scrimColor
和 app:drawerListener
:code
<android.support.v4.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
复制代码
有时候 view
的属性名和 set()
方法名并不匹配。好比 ImageView
有一个 android:tint
属性,对应的方法名倒是 setImageTintList(ColorStateList)
,这时咱们可使用 BindingMethods
注解,BindingMethods
用于注解一个类,它能够包含多个 BindingMethod
注解,BindingMethod
注解就声明了 view
属性要匹配哪一个 set()
方法:rem
@BindingMethods(value = [
BindingMethod(
type = android.widget.ImageView::class,
attribute = "android:tint",
method = "setImageTintList")])
复制代码
上面示例代表了:ImageView
的 android:tint
属性,须要调用 setImageTintList()
方法。get
有时候 view
属性须要自定义绑定逻辑。好比 view
属性有 android:paddingLeft
属性却没有 setPaddingLeft(int)
方法,可是有 setPadding(int left, int top, int right, int bottom)
方法,这时候咱们须要自定义逻辑。这时,咱们使用 BindingAdapter
注解一个 static
方法,以下所示:string
@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
复制代码
上面的示例代表了:View
的 android:paddingLeft
的属性,会调用 view
的 setPadding(int left, int top, int right, int bottom)
。
注意,该方法的参数很重要,第一个参数指明了 view
的类型,第二个参数指明了绑定表达式的返回值是 Int
类型。
若是自定义的适配器和系统的适配器有冲突,自定义的适配器会覆盖系统的。
BindingAdapter
注解能够接收多个参数,以下所示:
@BindingAdapter("imageUrl", "error")
fun loadImage(view: ImageView, url: String, error: Drawable) {
Picasso.get().load(url).error(error).into(view)
}
复制代码
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
复制代码
上述示例代表了:view
类型是 ImageView
,有两个属性 imageUrl
和 error
,这两个属性对应绑定表达式的返回类型分别是 String
和 Drawable
。
注意,只有当 ImageView
同时有 imageUrl
和 error
两个属性时,上述方法才会被调用。若是你但愿 ImageView
有任一属性均可以调用,能够声明 requireAll = false
:
@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String, placeHolder: Drawable) {
if (url == null) {
imageView.setImageDrawable(placeholder);
} else {
MyImageLoader.loadInto(imageView, url, placeholder);
}
}
复制代码
有时BindingAdapter
可能须要属性的旧值,能够这么使用:
@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
if (oldPadding != newPadding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
}
复制代码
@BindingAdapter("android:onLayoutChange")
fun setOnLayoutChangeListener(
view: View,
oldValue: View.OnLayoutChangeListener?,
newValue: View.OnLayoutChangeListener?
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (oldValue != null) {
view.removeOnLayoutChangeListener(oldValue)
}
if (newValue != null) {
view.addOnLayoutChangeListener(newValue)
}
}
}
复制代码
上述示例中,第二个参数是旧值,第三个参数是新值。
在绑定表达式中,表达式的返回值类型须要与对应的 set()
方法接收的参数类型一致,若是不一致咱们须要在绑定表达式中进行转换,例如 android:text=@{user.age}
,user.age
返回值类型是 Int
,setText(String text)
接收的参数类型是 String
,此时咱们就须要进行转换:
android:text=@{String.valueOf(user.age)}
复制代码
上述示例中:调用了 String.valueOf()
方法,把 Int
转换为了 String
。
有些场景是固定地在两种类型之间进行转换,这时候可使用自定义转换。好比 view
的 android:background
属性接收 Drawable
类型的数据,可是在绑定表达式中使用的倒是 Int
类型,以下所示:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
复制代码
这时候,Int
须要转换为 Drawable
,咱们可使用 BindingConversion
注解一个静态方法,以下所示:
@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)
复制代码
注意,绑定表达式中的返回值类型必须是固定的,以下所示是错误的:
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
复制代码
上面示例中,绑定表达式的返回值类型是不肯定的,多是 Drawable
或者 Int
,这种使用方法是不行的。