BindingAdapter :绑定适配器,是 Jetpack DataBinding 中用来扩展布局 xml 属性行为的注解,容许你针对布局 xml 中的一个或多个属性进行绑定行为扩展,这个属性能够是自定义属性,也能够是原生属性。这个扩展行为能够是简单的ViewModel属性与控件赋值绑定,也能够是关联某个控件属性的额外操做,例如在设置属性以前进行值域检查,或类型转换,或者统一处理一些事情。
例:java
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@{"http://****/**.jpg"}" />
上例中:src是默认的控件属性,而src须要使用一个资源ID,来完成赋值,并不支持网络地址来获取设置图片,此时就能够经过 BindingAdapter 来扩展行为,使其具有使用一个网络地址,而且从网络下载图片并显示的能力。android
@BindingAdapter("android:src") public static void setSrc(ImageView view, String bitmapPath) { if(ObjectUtil.nonNull(bitmapPath)) { GlideApp.with(view.getContext()) .load(bitmapPath) .into(view); } else { view.setImageDrawable(null); } }
这样就完成了对于 android:src 布局属性的行为扩展。此时咱们能够直接设置地址路径来完成网络下载图片并复制给 ImageView 的能力了。编程
BindingAdapter 是基于 APT 注解技术工做的,APT 能够在项目构建时更具相关编写规则生成特定代码完成一些指定功能的技术。
BindingAdapter 有两个属性,value 是一个 String[] ,requireAll 是一个boolean类型:
value 用来描述 XML 中感兴趣的关联属性,这里是个数组,说明一个扩展方法能够同时关注多个 XML 属性。这个很重要,有时候咱们可能在对控件进行赋值时,须要同时给定多个值,而 XML 属性值却一次只能指定一个变量,这样可能会让咱们不的不为此去扩展一个复合对象来完成这样的赋值,可是实际上并不须要那样。
requireAll 用来对 value 补充说明的,这个值默认是 true,表示使用这个适配规则必须在 XML 中声明该注解关注全部属性值,不然编译时会报错,而 false 则不须要,他容许只使用关注的部分或所有属性来使用该规则。数组
例: 当requireAll = true 时网络
@BindingAdapter(value = {"galleryEffectWidthLeft", "galleryEffectWidthRight", "galleryEffectPageMargin", "galleryEffectScale"}, requireAll = true) public static void setBannerGalleryEffect(Banner banner, int galleryWidthLeft, int galleryWidthRight, int galleryPageMargin, float galleryScale) { banner.setBannerGalleryEffect(galleryWidthLeft, galleryWidthRight, galleryPageMargin, galleryScale); }
//正确 galleryEffect 相关4个熟悉都设置了 <com.youth.banner.Banner android:layout_width="match_parent" android:layout_height="175dp" android:layout_marginTop="90dp" app:adapter="@{recommendVipZoneViewModel.bannerAdapter}" app:banner_radius="8dp" app:galleryEffectWidthLeft="@{7}" app:galleryEffectWidthRight="@{8}" app:galleryEffectPageMargin="@{9}" app:galleryEffectScale="@{0.85f}" /> //错误,app:galleryEffectScale 属性未设置状况 <com.youth.banner.Banner android:layout_width="match_parent" android:layout_height="175dp" android:layout_marginTop="90dp" app:adapter="@{recommendVipZoneViewModel.bannerAdapter}" app:banner_radius="8dp" app:galleryEffectWidthLeft="@{7}" app:galleryEffectWidthRight="@{8}" app:galleryEffectPageMargin="@{9}" />
例: 当requireAll = false 时app
@BindingAdapter(value = {"galleryEffectWidthLeft", "galleryEffectWidthRight", "galleryEffectPageMargin", "galleryEffectScale"}, requireAll = false) public static void setBannerGalleryEffect(Banner banner, int galleryWidthLeft, int galleryWidthRight, int galleryPageMargin, float galleryScale) { banner.setBannerGalleryEffect(galleryWidthLeft, galleryWidthRight, galleryPageMargin, galleryScale); }
//正确,须要注意的是,此时少了的galleryEffectScale属性可能会接受一个默认只好比这里float可能为0.0 <com.youth.banner.Banner android:layout_width="match_parent" android:layout_height="175dp" android:layout_marginTop="90dp" app:adapter="@{recommendVipZoneViewModel.bannerAdapter}" app:banner_radius="8dp" app:galleryEffectWidthLeft="@{7}" app:galleryEffectWidthRight="@{8}" app:galleryEffectPageMargin="@{9}" />
关于 BindingAdapter 注解自己已经有所了解。如何使用
首先,关于使用 BindingAdapter 描述的函数签名,参数列表必须按照如下固定形式出现:ide
// 类构建能够随意,APT会在构建时扫描全局代码 public class ViewAttrAdapter { // 须要注意的是 XML标签 关注了几个,参数列表就须要写几个对应的接受参数。且关注控件类必须在第一个参数。 @BindingAdapter({xml属性标签, ...}) public static void 函数名(关注的控件类 view, xml属性标签值 value, ...){ // 行为 } // 能够包含多个函数 ..... }
而在XML布局中,咱们应该使用 BindingAdapter 标签对应的标签类型进行赋值,切必须使用@{}做为值包裹,这是为了提供给APT解析XML是区别普通赋值的方式。函数
<View android:layout_width="match_parent" android:layout_height="175dp" app:xml属性标签="@{函数参数接受类型的值}" />
须要注意的是绑定解析的触发规则:布局
// 这个限定使用时必定是android:src才能匹配 @BindingAdapter("android:src") // 这个限定使用时 app:src 和 android:src 均可以匹配,但须要注意的是,android必须是在自定义属性声明的XML中有描述过的,如 attrs.xml 中 @BindingAdapter("src")
触发解析的属性必须知足 标签="@{value}" 这里的 @{} 必定不能丢。学习
最后总结:BindingAdapter 提供了一个高自由的切片编程能力,容许在xml解析是绑定扩展行为,能够帮助完成不少事情,如事件监听,属性赋值,类型转换,统一业务处理,好比埋点处理,防重按等等。而 BindingAdapter 仅仅是Databinding中一个使用较多的注解,以后会学习更多相关注解帮助扩展双向绑定,双向赋值之类的事情。(一上属于我的理解,若有不一样想法,能够沟通修改,也会不时更新)