Android DataBinding 双向绑定

时间:2022-01-18 09:27:13

之前 databinding 框架并不支持 双向绑定,最新的版本支持了,但是用起来还算方便
以前使用的时候 是这样绑定的

 <CheckBox
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:checked="@{checked}"
   />

现在只需要在对应的属性 @{} 改为 @={}

想看下 具体他是那里配置这个东西的,发现 这些都是在这个包里面

android.databinding.adapters

然而 用checkbox 来说,这个包里面并没有checkbox 专用的 adapter,但是发现了这个CompoundButtonBindingAdapter,ok 应该就是这里了

然后跟踪到里面发现多了两个注解

@InverseBindingMethods({
        @InverseBindingMethod(type = CompoundButton.class, attribute = "android:checked"),
})

还有方法

 @BindingAdapter(value = {"android:onCheckedChanged", "android:checkedAttrChanged"},requireAll = false)
    public static void setListeners(CompoundButton view, final OnCheckedChangeListener listener,
            final InverseBindingListener attrChange) {
        if (attrChange == null) {
            view.setOnCheckedChangeListener(listener);
        } else {
            view.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if (listener != null) {
                        listener.onCheckedChanged(buttonView, isChecked);
                    }
                    attrChange.onChange();
                }
            });
        }
    }

发现 多了个 android:checkedAttrChanged,这个事件绑定 这个应该是根据上面的那个 InverseBindingMethod attribute =”android:checked” 来命名的,然后方法参数也多了个 listenerfinal InverseBindingListener attrChange, 这个会在 你使用@=的时候 会注入进来。

具体的还没试试自己写的view 的其他属性双向绑定,应该自定义view 要双向绑定属性也需要自己写这样的adapter

下面是仿照 写的一个edittext 双向绑定
View

package com.ygsoft.testbinding;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.EditText;

/** * Created by chenzipeng on 2016/6/22. */
public class AView extends EditText {

    private String name;

    public AView(Context context) {
        super(context);
    }

    public AView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Adapter

package com.ygsoft.testbinding;

import android.databinding.BindingAdapter;
import android.databinding.BindingMethod;
import android.databinding.BindingMethods;
import android.databinding.InverseBindingListener;
import android.databinding.InverseBindingMethod;
import android.databinding.InverseBindingMethods;
import android.databinding.adapters.ListenerUtil;
import android.text.Editable;
import android.text.TextWatcher;

/** * Created by chenzipeng on 2016/6/22. */

@BindingMethods({
        @BindingMethod(type = AView.class, attribute = "name", method = "setName")//定义绑定的方法
})

@InverseBindingMethods({
        @InverseBindingMethod(type = AView.class, attribute = "name")//这里有个event属性,如果不填默认event为 attribute+"AttrChanged" ,比如这里就是nameAttrChanged
})
public class AViewBindingAdapter {

    @BindingAdapter(value = {"nameAttrChanged"}, requireAll = false)//这里的evnet 与 @InverseBindingMethod 的event属性相同,requireAll这里意义不明,有可能在多个参数的时候要求所有都要注入
    public static void setName(AView aView, final InverseBindingListener nameAttrChange) {

        TextWatcher newWatcher = 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) {
                nameAttrChange.onChange();
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        };

        TextWatcher oldWatcher = ListenerUtil.trackListener(aView, newWatcher, R.id.textWatcher);

        if (nameAttrChange != null) {
            aView.addTextChangedListener(newWatcher);
        }

        if (oldWatcher != null) {
            aView.removeTextChangedListener(oldWatcher);
        }
    }

}