mBinding.myText.setText(“This is a new text”);
用过ButterKnife的同学可能都知道,ButterKnife
出过一次与gradle
版本不兼容的事故,但是DataBinding
是与gradle
打包在一起发布的,一般不会出现这种问题,如果你不想用ButterKnife
但有不想让DataBinding
的风格的写法入侵你的xml
太狠的话,只使用android:id
将会是一个不错的选择.
2.4 正向绑定
某些第三方View
是肯定没有适配DataBinding
的,业界虽然一直说MVVM
好,但现在MVP
的开发方式毕竟还是主流,虽然这种情况我们可以用android:id
,然后在Activity
/Fragment
中解决,但有时候我们想直接在xml
中配置,以消除一些样板代码,这时候就需要自定义正向绑定.
2.4.1 自定义正向绑定适配器
我们可以使用@BindingAdapter
自定义在xml
中可使用的View
属性,名字空间是不需要的,加了反而还会给你警告.
@Target(ElementType.METHOD)
public @interface BindingAdapter {
/**
- 与此绑定适配器关联的属性。
*/
String[] value();
/**
- 是否必须为每个属性分配绑定表达式,或者是否可以不分配某些属性。
- 如果为false,则当至少一个关联属性具有绑定表达式时,将调用BindingaAapter。
*/
boolean requireAll() default true;
}
//@BindingAdapter需要一个静态方法,该方法的第一个参数是与该适配器兼容的View类型
//从第二个参数开始,依次是你自定义的属性传进来的值.
//使用requireAll来指定这些属性是全部需要,还是只要一个就可以
//如果requireAll = false,触发适配器绑定时,没有被设置的属性将获得该类型的默认值
//框架优先使用自定义的适配器处理绑定
@BindingAdapter(value = {“load_async”, “error_handler”},requireAll = true)
public static void loadImage(ImageView view, String url, String error) {
Glide.with(view)
.load(url)
.error(Glide.with(view).load(error))
.into(view);
}
//在xml中使用它(下面那两个网址都不是实际存在的)
2.4.2 第三方View适配
DataBinding
风格的xml
还能在一定程度上适配第三方View
//如果你的自定义View中有这么一个Setter↓
public class RoundCornerImageView extends AppCompatImageView{
//…
public void setRadiusDp(float dp){
//TODO
}
}
//那么你可以在xml中使用radiusDp来使用它
<org.kexie.android.ftper.widget.RoundCornerImageView
radiusDp=“@{100}”
android:id=“@+id/progress”
android:layout_width=“match_parent”
android:layout_height=“match_parent”
android:layout_gravity=“center”
android:scaleType=“centerCrop”
android:src=“@drawable/progress”/>
//它会自己为你去找名称为setRadiusDp并且能接受100为参数的方法.
2.4.3 xml中的属性重定向
使用@BindingMethod
来将xml
属性重定向:
@Target(ElementType.ANNOTATION_TYPE)
public @interface BindingMethod {
//需要重定向的View类型
Class type();
//需要重定向的属性名
String attribute();
//需要重定向到的方法名
String method();
}
//这是DataBinding源码中,DataBinding对于系统自带的TextView编写的适配器
//这是androidx.databinding.adapters.TextViewBindingAdapter的源码
@BindingMethods({
@BindingMethod(type = TextView.class, attribute = “android:autoLink”, method = “setAutoLinkMask”),
@BindingMethod(type = TextView.class, attribute = “android:drawablePadding”, method = “setCompoundDrawablePadding”),
@BindingMethod(type = TextView.class, attribute = “android:editorExtras”, method = “setInputExtras”),
//…
})
public class TextViewBindingAdapter {
//…
}
//这样就可以建立起xml中属性与View中Setter的联系
2.4.4 添加转换层
使用@BindingConversion
为添加转换层
@BindingConversion
public static ColorDrawable toDrawable(int color) {
return new ColorDrawable(color);
}
//可以把color整形转换为android:src可接受的ColorDrawable类型
//但是转换只适用于直接的赋值
//如果你写了复杂的表达式,比如使用了?:这种三元运算符
//那就照顾不到你了
2.5 反向绑定
有正向绑定就一定有反向绑定,正向绑定和反向绑定一起构成了双向绑定.
在我们之前编写的DataBinding
表达式中,比如TextView
中android:text
之类的属性我们都是直接赋值一个String
过去的,这就是正向绑定,我们给View
的值能够直接反应到View
上,而反向绑定就是View
值的变化和也能反应给我们.
2.5.1 使用双向绑定
所有使用之前所有使用@{}
包裹的都是正向绑定,而双向绑定是@={}
,并且只支持变量,字段,Setter
(比如User#setName
,就写@={user.name}
)的直接编写并且不支持复杂表达式
2.5.2 兼容LiveData与ObservableField
实际上,android:text
不只能接受String
,当使用双向绑定时,它也能接受MutableLiveData<String>
和ObservableField<String>
作为赋值对象,这种赋值会将TextView
的android:text
的变化绑定到LiveData(实际上是MutableLiveData)
或者是ObservableField
上,以便我们在View
的控制层(Activity
/Fragment
)更好地观察他们的变化.
当然除了ObservableField
在androidx.databinding
包下还有不装箱的ObservableInt
,ObservableFloat
等等.
但是为了支持LiveData
我们必须开启第二版的DataBinding APT
.
在你的gradle.properties
添加
android.databinding.enableV2=true
现在我们可以通过LiveData(实际上是MutableLiveData)
将android:text
的变化绑定到Activity
/Fragment
//xml