美文网首页
DataBinding(四)属性设置

DataBinding(四)属性设置

作者: timshinlee | 来源:发表于2018-03-21 17:28 被阅读0次

1. 默认setter

对于设置了DataBinding表达式的XML属性,DataBinding会根据属性表达式的返回值查找该属性的setter方法,比如android:text="@{"str"}"属性是去找setText(String)方法,所以表达式的返回值类型是十分重要的,影响着DataBinding查找的具体方法。

如果View不提供某个属性的XML属性,但是其实包含了该属性的setter,这时候可以直接使用属性名,DataBinding会自动帮我们调用它的setter,比如DrawerLayout的xml没有scrimColor和drawerListener属性,但是存在其setter方法,则可以如下声明:

<android.support.v4.widget.DrawerLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:scrimColor="@{@color/scrim}"
    app:drawerListener="@{fragment.drawerListener}"/>

2. 重命名setter

如果属性名存在且有设置该属性的方法,但是方法名不符合传统setter规范,例如tint属性存在setImageTintList()方法,则可以通过@BindingMethods注解来绑定属性名及其设置方法:

@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})

3. 自定义setter

假如不存在刚好设置该属性的方法,可以通过@BindingAdapter注解自定义属性所要调用的静态方法,例如在XML中自定leftPadding属性,命名空间在这里是忽略掉的,Activity中添加以下代码:

@BindingAdapter("android:leftPadding")
public static void setLeftPadding(View view, int leftPadding){
    view.setPadding(leftPadding,view.getPaddingTop(),view.getPaddingRight(),view.getPaddingBottom());
}

通过这种方式可以把在XML不方便进行的操作转移到Java代码中,或者复用Java代码中已有的方法。BindingAdapter方法可以放置到Activity当中或者另外定义一个类用来存放BindingAdapter方法。

BindingAdapter方法可以接收多个参数,比如

@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);
}

<!-- XML -->
<ImageView app:imageUrl="@{venue.imageUrl}"
app:error="@{@drawable/venueError}"/>

但是只有当ImageView中使用了imageUrl和error属性,并且属性类型与方法类型相对应才会调用定义的BindingAdapter方法。

3.1 获取原值

BindingAdapter的方法可以获取到原先的值,此时方法的声明应该是列出所有的属性原值,然后才是新的值:

@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());
   }
}

3.2 事件自定义处理

事件处理只能用在带有单个方法的接口或者抽象类上,比如说:

@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(),那我们就必须手动创建两个接口来区分开:

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewDetachedFromWindow {
    void onViewDetachedFromWindow(View v);
}

@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
public interface OnViewAttachedToWindow {
    void onViewAttachedToWindow(View v);
}

因为改变一个监听器会影响到另外一个,所以必须要有三个Binding Adapter,两个是单独一个方法回调的,还有一个是所有方法回调的。

@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来操作监听器,而不是单个的set方法。android.databinding.adapters.ListenerUtil这个类帮忙记录设置的监听器,所以我们才有办法去移除掉。

上述代码的@TargetApi(VERSION_CODES.HONEYCOMB_MR1)注释表明从该api开始才会生成监听器,这个是根据添加监听器方法addOnAttachStateChangeListener(View.OnAttachStateChangeListener)所要求的。

相关文章

网友评论

      本文标题:DataBinding(四)属性设置

      本文链接:https://www.haomeiwen.com/subject/ceogqftx.html