DataBinding支持使用自定义的方法来处理View。
自动检测自定义方法
假设现在有一个自定义View,其中有一个自定义方法setMyViewBgColor。
public class MyView extends AppCompatTextView {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setMyViewBgColor(int color) {
setBackgroundColor(color);
}
}
在xml中
<com.qianfanyun.databinding.MyView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="aaaa"
app:myViewBgColor="@{@color/colorPrimary}"
/>
这时会发现,界面上View的背景变成了colorPrimary的颜色。
DataBinding会自动检测View中的set方法,如果与自定义属性的名称和参数一致,会进行调用。这个还是很方便的,省去了我们定义自定义属性的时间。
自定义关联的属性和方法,这样对方法命名就没有强制要求了
@BindingMethods({
@BindingMethod(type = MyView.class,
attribute = "bg",
method = "setMyViewBgColor"),
})
public class MyView extends AppCompatTextView {
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setMyViewBgColor(int color) {
setBackgroundColor(color);
}
}
自定义方法处理xml中的属性
DataBinding运行自定义方法,对应xml中的自定义属性。下面以图片加载为例
首先创建一个工具类,添加注释@BindingAdapter。value表示自定义属性的名称,从方法第二个参数开始一一对应。第一个参数表示哪种类型的View支持这个自定义方法。
public class ImageUtil {
@BindingAdapter(value = {"image"})
public static void loadImage(ImageView imageView, String url) {
ImageLoader.get().loadImage(imageView, url);
}
}
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
app:image='@{"https://ws1.sinaimg.cn/large/0065oQSqly1g0ajj4h6ndj30sg11xdmj.jpg"}'
/>
这样,网络图片就成功加载出来了。
这种方式也支持多个参数
@BindingAdapter(value = {"image","round"}, requireAll = false)
public static void loadImage(ImageView imageView, String url, boolean round) {
if (round) {
ImageLoader.get().loadImage(imageView, url, ImageOptions.option().circleCrop().build());
} else {
ImageLoader.get().loadImage(imageView, url);
}
}
requireAll表示是否所有参数都必须填
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
app:image='@{"https://ws1.sinaimg.cn/large/0065oQSqly1g0ajj4h6ndj30sg11xdmj.jpg"}'
app:round="@{true}" />
这样加载出来的就是圆形图片
实际上,通过这种方式,可以解决使用Glide加载图片时,无法在xml中定义属性的问题,通过预定义各种参数,可以将Glide所有支持的属性,在xml中实现。
监听拓展
DataBinding可以对View原有的监听进行拓展。这里举两个例子
- 支持在xml中调用任意类的方法处理OnTextChanged事件。
- 防止多次点击的OnClick实现。
case 1
定义一个处理android:onTextChanged
的方法。
public class AdapterUtils {
@BindingAdapter("android:onTextChanged")
public static void setTextChangedListener(EditText editText, final OnTextChangedListener listener) {
if (listener != null) {
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
listener.onTextChanged(s.toString());
}
@Override
public void afterTextChanged(Editable s) {
}
};
TextWatcher oldWatcher = ListenerUtil.trackListener(editText, textWatcher, R.id.textWatcher);
if (oldWatcher != null) {
editText.removeTextChangedListener(oldWatcher);
} else {
editText.addTextChangedListener(textWatcher);
}
}
}
}
第二个参数是我们自定义的一个接口。DataBinding只支持单一方法的接口,因此自定义了一个新的接口。
public interface OnTextChangedListener {
void onTextChanged(String text);
}
public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
binding.setMainActivity(this);
}
public void onTextChanged(String str){
Log.d("x","onTextChanged--->"+str);
}
}
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity">
<data>
<variable
name="MainActivity"
type="com.qianfanyun.databinding.MainActivity" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical">
<EditText
android:layout_width="200dp"
android:layout_height="wrap_content"
android:onTextChanged="@{(str)->MainActivity.onTextChanged(str)}" />
</LinearLayout>
</layout>
最终在text改变时,会输出当前的text。
这样看起来代码更多了。但实际上这个adapter可以是通用的,以后所有的OnTextChanged只需要在某个类中定义一个公共方法,并在xml中引用即可。
case 2
定义一个代理方法。使用工具方法判断是否在短时间内重复点击。
@BindingAdapter("android:onClick")
public static void setClickListener(View view, final View.OnClickListener listener){
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (Utils.isFastDoubleClick()){
return;
}
listener.onClick(v);
}
});
}
工具方法
public class Utils {
private static long lastClickTime;
public static boolean isFastDoubleClick() {
long time = System.currentTimeMillis();
long timeD = time - lastClickTime;
if (0 < timeD && timeD < 800) {
return true;
}
lastClickTime = time;
return false;
}
}
在xml中调用方法
<Button
android:layout_width="200dp"
android:layout_height="wrap_content"
android:text="Button"
android:onClick="@{()->MainActivity.onButtonClick()}"
/>
在MainActivity中定义
public void onButtonClick(){
Log.d("x","onClick");
}
测试下来确实短时间内快速点击不会重复触发点击事件
总结
总体来说,DataBinding支持3种方式对xml中的属性进行拓展
- View的自定义方法
- set前缀自动识别
- 手动绑定属性和自定义方法
- Adapter自定义View的属性
- 支持自定义属性名
- 自定义处理属性的方法
- 支持多个属性作为方法的参数
- Adapter拓展View原有的监听
- 只支持单个函数的接口
- 可以实现对原有监听的拦截
网友评论