binding adapters用来设置值,提供自定义的绑定逻辑等。
当绑定的值发生变化时,绑定类会自动调用view的setter方法。我们可以提供自定义逻辑来选择调用的方法,也可以让data binding 库自动选择。
自动方法选择
比如对于名称为example的属性来说,库会自动setExample(arg)方法,在搜索过程中,只会考虑方法名称和参数,不考虑命名空间。
例如,对于表达式android:text="@{user.name}",库会查找方法setText(arg),此方法接受的参数类型是user.getName()返回的类型。
<android.support.v4.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
对于存在setter方法,不存在对应属性的情况,data binding仍然起作用。我们可以给任意setter方法创建属性。比如DrawerLayout没有属性,但是有setter方法。上面的代码中就自动使用了setScrimColor(int) 和 setDrawerListener(DrawerListener)两个方法。
@BindingMethods({
@BindingMethod(type = "android.widget.ImageView",
attribute = "android:tint",
method = "setImageTintList"),
})
BindingMethod注解可以把属性和方法进行对应,比如上例中,我们把android:tint和setImageTintList关联在一起,而不是setTint()。
提供自定义逻辑
有些属性需要自定义的绑定逻辑,当对应属性值发生变化时触发自定义的逻辑。
我们可以定义static的带有@BindingAdapter注解的方法来自定义绑定逻辑。
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
方法的第一个参数指当前的view,第二个参数代表binding表达式接受的参数。
在binding adapter方法中,我们一次可以定义多个属性。
@BindingAdapter({"imageUrl", "error"})
public static void loadImage(ImageView view, String url, Drawable error) {
Picasso.get().load(url).error(error).into(view);
}
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
此时,只有imageUrl和error同时使用的时候,loadImage才会触发。如果你希望,两者中任意一个值设置之后触发方法调用,那可以设置requireAll=false
@BindingAdapter(value={"imageUrl", "placeholder"}, requireAll=false)
public static void setImageUrl(ImageView imageView, String url, Drawable placeHolder) {
if (url == null) {
imageView.setImageDrawable(placeholder);
} else {
MyImageLoader.loadInto(imageView, url, placeholder);
}
}
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int oldPadding, int newPadding) {
if (oldPadding != newPadding) {
view.setPadding(newPadding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
}
我们可以同时在方法中处理旧值和新值,对于只有一个方法的接口或抽象类也可以这样使用,但是如果多余一个方法,则需要拆成多个类。
@BindingAdapter("android:onLayoutChange")
public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue,
View.OnLayoutChangeListener newValue) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (oldValue != null) {
view.removeOnLayoutChangeListener(oldValue);
}
if (newValue != null) {
view.addOnLayoutChangeListener(newValue);
}
}
}
对象转换
如果binding表达式中返回一个object,那系统会查找对应的方法,并自动的转换为对应类型的参数。如果方法接受的参数也是模糊的,那需要自定义转换。
比如,一个属性值接受Drawable,但你提个的是int,这时候就需要转换。
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
return new ColorDrawable(color);
}
在这个方法中,需要返回一个对应类型的值。
网友评论