本文为菜鸟学习笔记兼翻译练习用,翻译可能会不准确,细节请以原文为准,如有不足之处还请见谅,若能斧正,小弟不胜感激。原文地址:Google DataBinding Library
属性Setter
无论何时当一个绑定值变化,创建的绑定类必须调用有绑定表达式的VIew的setter方法。DataBinding框架有数种方法确定要调用哪个方法来设置值。
自动Setter
对于一个属性,DataBinding尝试各种方法设置属性。属性的命名空间并不重要,只需要属性本身的名称。例如,一个TextView的属性android:text对应的表达式会去查找一个setText(String)的方法。如果表达式返回的是int型,DataBinding会查找setText(int)方法。注意要让表达式返回正确的类型,如有必要就进行强制转换。特别注意DataBinding在没有属性匹配给予的名字的情况下仍然会工作。你可以为任意setter简单的“创造”一个属性。例如,DrawerLayout没有任何特有属性,但是有特有的setter。你可以这样使用自动setter:
<android.support.v4.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}"/>
重命名Setter
有些属性的setter和名字不匹配。对于这些方法,可以通过BindingMetods注解将属性和setter联系在一起。这必须和一个类联系在一起并且包含BindingMethods注解,每个要重命名的方法都要有。例如,android:tint属性和setImageTintList(ColorStateList)联系在一起,而不是setTint:
@BindingMethods({
@BindingMethod(type = "android.widget.ImageView",
attribute = "android:tint",
method = "setImageTintList"),
})
这不会让开发者需要去重命名Setter;android框架属性已经实施了相关工作。
自定义Setter
一些属性需要自定义绑定逻辑。比如,android:paddingLeft属性没有相关的setter。取而代之的是存在setPadding(left, top, right, bottom)方法。一个用BindingAdapter注解修饰的静态绑定适配器方法允许开发这自定义一个属性的setter如何被调用。
Android属性已经有BindingAdapters创建了。例如,下边是paddingLeft的Setter的实现方法:
@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom());
}
Binding adapter对其他的自定义类型也十分有用。例如,一个自定义loader可以切换线程加载图片。
当存在冲突是开发者自定义的binding adapter会覆写默认的数据绑定适配器。
你也可以使用接收多个参数的适配器:
@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageView app:imageUrl="@{venue.imageUrl}"
app:error="@{@drawable/venueError}"/>
这个适配器在imageUrl和error都用到时被使用,iamgeUrl是String型,error是drawable。
- 在匹配时,自定义命名空间会被忽略。
- 你也可以为android的命名控件写适配器。
绑定适配器可能会随意的从它们的handler取旧值。一个会取旧值和新值的方法应该有所有的旧值和紧随其后的新值。
@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());
}
}
事件handler可以被接口或抽象类的抽象方法使用。例如:
@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);
}
}
}
当一个监听器有多个方法时,它必须要分成多个监听器。例如, View.OnAttachStateChangeListener有两个方法: onViewAttachedToWindow()和 onViewDetachedFromWindow()。我们必须要创建两个接口来区别它们的属性和handler。
@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
void onViewDetachedFromWindow(View v);
}
@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
void onViewAttachedToWindow(View v);
}
因为改变一个监听器会影响到其他监听器,我们必须使用三个不同的绑定适配器,一个是同时调用两个属性的,还有两个是分别对应单个属性的:
@BindingAdapter("android:onViewAttachedToWindow")
public static void setListener(View view, OnViewAttachedToWindow attached) {
setListener(view, null, attached);
}
@BindingAdapter("android:onViewDetachedFromWindow")
public static void setListener(View view, OnViewDetachedFromWindow detached) {
setListener(view, detached, null);
}
@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"})
public static void setListener(View view, final OnViewDetachedFromWindow detach,
final OnViewAttachedToWindow attach) {
if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) {
final OnAttachStateChangeListener newListener;
if (detach == null && attach == null) {
newListener = null;
} else {
newListener = new OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
if (attach != null) {
attach.onViewAttachedToWindow(v);
}
}
@Override
public void onViewDetachedFromWindow(View v) {
if (detach != null) {
detach.onViewDetachedFromWindow(v);
}
}
};
}
final OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view,
newListener, R.id.onAttachStateChangeListener);
if (oldListener != null) {
view.removeOnAttachStateChangeListener(oldListener);
}
if (newListener != null) {
view.addOnAttachStateChangeListener(newListener);
}
}
}
上边的例子有一些与众不同,因为View使用add和remove的方法处理监听器,代替了对View.OnAttachStateChangeListener使用set方法。android.databinding.adapters.ListenerUtil类可以帮助我们记录之前的监听器痕迹以便于从绑定adapter中移除。
通过用@TargetApi(VERSION_CODES.HONEYCOMB_MR1)修饰OnViewDetachedFromWindow和OnViewAttachedToWindow接口,数据绑定代码产生器可以知道监听器只能在Honeycomb MR1和更新的设备上创建监听器,同版本由addOnAttachStateChangeListener(View.OnAttachStateChangeListener)支持。
下一篇翻译Converters,估计要翻译完了。
本文深入探讨了Data Binding中属性Setter的使用方式,包括自动Setter、重命名Setter和自定义Setter等,介绍了如何通过不同方法设置属性值,并给出了具体的实现示例。
属性Setter&spm=1001.2101.3001.5002&articleId=78661884&d=1&t=3&u=ce376158d9ba414fa6b700388246abdd)
335

被折叠的 条评论
为什么被折叠?



