双向绑定的方法有几种这里用到的是借助@BindingAdapter
来实现。
无项
就是xml里面有一个model,你设置进去了,它就更新就是了。
纯单项 ,所谓单项 ,就是你调用一个值set就可以让view变化,这需要@Bindable
@ notifyPropertyChanged(BR.title);
双项是值 可以修改值来改变view的状态 或者通过修改view的状态来实现修改model的值 这就是你中有我我中有你.
model继承extends BaseObservable
然后set里面设置
这需要@BindingAdapter
@InverseBindingAdapter
纯@BindingAdapter
是方便xml里面设置用的。 比如里面定义 @BindingAdapter("intvalue")
就可以使用xxx:@{xxx.xx}
class BBB extends BaseObservable{
@Bindable//有了注解这个才会生成BR.title
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
notifyPropertyChanged(BR.title);//双向绑定通知改变,不通知就不会生效。
}
}
单项绑定的我不想再说了,直接上高阶代码
下面代码实现 int类型编辑框的双向生效,修改编辑框内容的时候model值变化,修改model值得时候编辑框内容变化。
任意创建一个类定义下面几个静态方法
第一个方法代表 修改view,
@BindingAdapter("intvalue")
public static void setTextIntValue(TextView view, int value) {
第二个方法代表修改model
@InverseBindingAdapter(attribute = "intvalue", event = "intvalueAttrChanged")
public static int getTextIntValue(TextView view) {
第三个方法代表修改model的触发条件在里面设置view监听然后调用onChange从而触发调用第二个方法。
@InverseBindingAdapter(attribute = "intvalue", event = "intvalueAttrChanged")
第二个方法的event对应的是第三个方法的@BindingAdapter("intvalueAttrChanged")
用法:
在xml里面定义
<EditText
app:intvalue="@={model.age}"
/>
触发原理:
编译后会生成一个databindimpl,它会根据注解生成viewbinding生成一个类,
里面的代码就是把第三个方法的代码拷贝一份进行设置监听,
当你修改编辑框内容的时候监听触发了,onChange,onChange()这是代表view改变,我之前说过是会通知model改变,model的改变为第二个方法,getxxint ,你可以尝试写死一个值,你会发现这个值在model里面生效了。
当你通过set器修改model的值,通过model里面定义的
notifyPropertyChanged(BR.title);/
就会触发view的修改,但是这里是个死循环,
这双向绑定不需要加notifyPropertyChanged(BR.title);
或者加一个判断,
当然我这里之所以还是加上了,是我监听的不对,我写在了onTextChanged里面。
直接不加上notifyPropertyChanged
也能修改,但是光标位置不对,感觉不太爽,所以解决方法就是调整一下回调通知或者不加判断。
/**
* 根据model的值来设置 view的值 双向绑定 ,setValue Model 不需要加notifyFieldChanage() 否则死循环 除非文本判断。
**/
@BindingAdapter("intvalue")
public static void setTextIntValue(TextView view, int value) {
// final TextWatcher oldValue = ListenerUtil.trackListener(view, null, R.id.textWatcher);
if(ParseUtil.parseInt(view.getText().toString()) ==value){//0 or "" ==0 找到死循环的原因了,现在不需要加这句话了。
return;
}
if(value==0){
view.setText("");//可以在失去焦点的时候设置。
}else{
view.setText(value + "");
}
// if(oldValue!=null){
// view.addTextChangedListener(oldValue);
}
/**
* 在onChange 里面调用本方法获得返回值, 然后来修改模型的值.
*
* @param view
* @return
*/
@InverseBindingAdapter(attribute = "intvalue", event = "intvalueAttrChanged")
public static int getTextIntValue(TextView view) {
return ParseUtil.parseInt(view.getText().toString());
}
@BindingAdapter("intvalueAttrChanged")
public static void intValueChangeBind(final TextView view,
final InverseBindingListener changeBindListener) {
TextWatcher watcher =null;
if(changeBindListener!=null){
watcher = 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) {
changeBindListener.onChange();
}
@Override
public void afterTextChanged(Editable s) {
}
};
}else{
}
// view.addTextChangedListener(watcher);//下面的话没有任何意义 //下面的话加不加都解决不了死循环的问题 只能用判断来解决死循环 addTextChangedListener可能是这句话导致
final TextWatcher oldValue = ListenerUtil.trackListener(view, watcher, R.id.textWatcher);
if (oldValue != null) {
view.removeTextChangedListener(oldValue);
}
if (watcher != null) {
view.addTextChangedListener(watcher);
}
}
更多databind请访问我的其它文章。
网友评论