本文的目标是阐述BindingAdapter使用方法并以点击事件为例
在介绍它之前,我们先讲一下,布局文件中的系统属性android:onClick="" ,不知道你有没有用过,其中双引号中间就是你要触发的事件名称。不需要用findViewById获取对应控件,然后再监听click事件,若是你用过请略过,若是没有过,我们看看怎么用的。
举个例子:
在布局文件中设置android:onClick=“clickEvent”
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="clickEvent"
android:src="@drawable/tes" />
在activity中新建一个clickEvent函数:
public void clickEvent(View v) {
Toast.makeText(this, "test", Toast.LENGTH_LONG).show();
}
这样就直接可以监听ImageView的单击事件,这样是不是很方便,为啥要介绍这个呢,是因为本文BindingAdapter也要采用同样的方式来实现,只是我们不采用系统的定义的属性,而是自己定义属性。
首先要讲一下attrs.xml,它是res/values目录下的一个文件,为什么讲它?因为它跟bindingadapter紧密相连。
<resources>
<attr name="backColor" format="color">
<enum name="redColor" value="1" />
<declare-styleable name="MyView">
<attr name="backColor"/>
declare-styleable>
resources>
以attr开头的代表着具体某个属性。
以declare-styleable代表的某个组。例如我想为一个view自定义一个属性,假设这个view为MyView,则MyView下面定义所有属性都属于MyView组,凡是继承它的都可以使用。当然也可以为系统控件加上自定义属性。
系统属性和自定义属性是有区别的,属性名前面有“android:”都是系统属性。自定属性名没有没有什么好说的,尽量不要和系统定义的属性名雷同。
若是和系统定义的属性一样,不设置format的话,就沿用系统的。若是设置的话,就是对系统属性的重定义,但是有些系统属性格式是无法修改的。
简单介绍一下属性的format:
reference 引用
color 颜色
boolean 布尔
integer 整型
dimension
float 浮点型
string 字符型
fraction 百分比
enum 枚举型
flag
自定义属性搞定了,其实没什么难度,那么接下来,我们要看看如何自定义属性和BindingAdapter建立连接的呢。其实也很简单,还是以一个例子来说明
<resources>
<declare-styleable name="View">
<attr name="onClickCommand" format="reference" />
declare-styleable>
resources>
这个属性name,就是BindingAdapter的关键。
它的一般格式为:
@BindingAdapter(value={“属性名1”,“属性名2”})
public static void 函数名(参数){
//函数内容
}
具体的实例如下:新建一个文件为ViewAdapter.java,并类中添加如下代码
@BindingAdapter(value = {"onClickCommand"}, requireAll = false)
public static void click(View view, final ClickCallBack bindingCommand) {
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (bindingCommand != null) {
bindingCommand.clickEvent();
Toast.makeText(view.getContext(), "it works", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(view.getContext(), "binding command is null", Toast.LENGTH_LONG).show();
}
}
});
}
BindingAdapter中value要和attrs.xml中自定义属性保持一致,否则绑定不成功。
绑定的函数一定要是static的,函数名没有具体的要求,函数里面的第一个参数为要绑定对象,我们绑定的为View,那就是View;
后面的参数就是各个属性,在布局文件中一定要按顺序进行,否则可能会报错。
还需要在布局文件中应用这个属性
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/tes"
binding:onClickCommand="@{viewmodel.mBindingCommand}"
/>
到目前为止,代码层面是没有问题,但是还不能用,因为还要binding。
ActivityMainBinding binding = DataBindingUtil.setContentView(this, getLayoutResId());
其中ActivityMainBinding是系统自动生成的,这一步实现布局文件和属性之间进行绑定,也就是可以实现单击事件了。
最后,我们不仅要是实现事件绑定还能在ViewModel中回调,因为需要对事件进行业务的处理
在ViewModel中,需要具体实现BindingAdapter的回到,如下:
public ClickCallBack mBindingCommand = new ClickCallBack() {
@Override
public void clickEvent() {
Log.e("tag", "click");
}
};
只需要在布局文件中绑定这个回调即可生效。
但是你发现回调对象为空,因为还需要设置
binding.setVariable(BR.viewmodel, mViewModel);
这样才是完整的BindingAdapter过程。
值得注意的是binding.setVariable(BR.viewmodel, mViewModel);必须在创建ViewModel之后,否则你绑定回调参数为空,因为ViewModel没有创建为空,可以看自动生成的代码,自动生成的代码也可调试。
若是你想统一对ImageView都用Glide进行加载图片,你就可以通过这个中方式实现
@BindingAdapter({"imageUrl"})
public static void loadImage(ImageView view, String u) {
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.mipmap.ic_launcher_round)
.error(R.mipmap.ic_launcher)
.priority(Priority.HIGH)
.diskCacheStrategy(DiskCacheStrategy.NONE);
Glide.with(view.getContext()).applyDefaultRequestOptions(options).load(u).transition(new DrawableTransitionOptions().crossFade(1000)).into(view);
}
代码量会很少,效率会很高。