热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

dataBinding之自定义双向绑定(一)

什么是双向绑定?其实在之前有一篇关于MVVM的文章中已经介绍过,比如登录的时候Edittext,当我们输入登录账号和密码时候,

什么是双向绑定?其实在之前有一篇关于MVVM的文章中已经介绍过,比如登录的时候Edittext,当我们输入登录账号和密码时候,不需要通过Edittext.getText()获取内容,而是自动更新到M层,相反,当更新M层相关内容,也会自动更新到EditText尽心展示。所以,双向绑定就是:V层->M层、M层->V层。
在官方的介绍中,有两种方式能够实现自定义双向绑定:


  • InverseBindingMethods+InverseBindingMethod+BindingAdapter
  • InverseBindingAdapter+BindingAdapter
    本篇文章讲解第一种方式,后续会讲解第二种方式。

一、InverseBindingMethods

在这里插入图片描述
该注解作用于类,官方的介绍是该注解,用于枚举属性、getter和事件相关联。并且value是InverseBindingMethod数组。


二、InverseBindingMethod

在这里插入图片描述
该注解作用于方法之上。


  • type:需要自定义属性的类。必填项,比如RatingBar.class
  • attribute:String类型。必填项,如android:rating
  • event:用于通知view层属性值变化。可选项,否则使用默认配置:如ratingAttrChanged
  • method:get方法,用于接收view层属性变化,通知Model层。可选项,否则使用默认配置:如getRating

三、BindingAdapter

在这里插入图片描述
该注解作用于方法之上。方法的第一个参数的类型必须为View类型,不然报错


  • value:自定义任意属性,比如android:rating
  • requireAll:boolean类型,可选项,返回true,所有的属性都需要支持,返回false,不需要支持所有属性。

四、自定义的属性是如何被调用的

比如在xml设置如下伪代码:

...<data><variablename&#61;"rt"type&#61;"Float" /></data><RatingBarandroid:layout_width&#61;"match_parent"android:layout_height&#61;"wrap_content"android:numStars&#61;"10"android:rt&#61;"&#64;&#61;{rt}"/>
...

编译时&#xff0c;编译器会扫描RatingBar使用databinding表达式的属性。这里会找到 android:rt。然后判断这个属性是不是RatingBar自有属性&#xff0c;如果是的话&#xff0c;会找对应的set方法(这里指setRt()方法)生成代码&#xff1b;如果不是自有属性&#xff0c;先找有没有对应且合适的set方法&#xff0c;有的话&#xff0c;就用set方法生成代码&#xff0c;没有的话&#xff0c;就会从所有定义的BindingAdapter中去找合适的方法。比如setRt()方法。


五、自定义双向绑定

&#64;InverseBindingMethods(value &#61; {&#64;InverseBindingMethod(type &#61; RatingBar.class,attribute &#61; "android:rating")
})
public class MyInverseBindingMethods {&#64;BindingAdapter("android:rating")public static void setRating(RatingBar view, float value) {if (view &#61;&#61; null) {return;}float rating &#61; view.getRating();if (rating &#61;&#61; value) {return;}//model->viewview.setRating(value);}&#64;BindingAdapter(value &#61; {"android:onRatingChanged", "android:ratingAttrChanged"},requireAll &#61; false)public static void setListener(RatingBar view,final RatingBar.OnRatingBarChangeListener listener,final InverseBindingListener attrListener) {if (attrListener &#61;&#61; null) {view.setOnRatingBarChangeListener(listener);} else {//view->modelview.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {&#64;Overridepublic void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {if (listener !&#61; null) {listener.onRatingChanged(ratingBar, rating, fromUser);}attrListener.onChange();}});}}
}

这段代码定义了RatingBar类的android:rating属性&#xff0c;由于没有定义event和method属性&#xff0c;所以event的属性默认为android:ratingAttrChanged&#xff0c;method的默认属性对应为getRating。其实RatingBar类已经提供了android:rating属性&#xff0c;这里为什么要重新定义&#xff1f;其实是为了防止双向绑定死循环的问题。当我们在布局中使用了databinding表达式&#xff0c;那么就会调用到setRating()方法&#xff0c;判断当前值和设置的值是否相同&#xff0c;避免循环设置。

下面说一下重点方法setListener()&#xff1a;
这里面的BindingAdapter多了两个属性


  • android:onRatingChanged
  • android:ratingAttrChanged

另外我们知道&#xff0c;这两个属性和setListener方法的参数是按照顺序对应的&#xff0c;所以android:onRatingChanged对应OnRatingBarChangeListener &#xff0c;android:ratingAttrChanged对应InverseBindingListener 。而我们又知道&#xff0c;android:ratingAttrChanged对应 &#64;InverseBindingMethodevent属性&#xff0c;所以最终event转换为InverseBindingListener。上面说到event属性用来双向绑定时对view的变化作出通知的 &#xff0c;所以最终试通过InverseBindingListener实现通知的&#xff0c;对应即 onChange() 方法


六、使用

布局文件

<?xml version&#61;"1.0" encoding&#61;"utf-8"?>
<layout xmlns:android&#61;"http://schemas.android.com/apk/res/android"xmlns:app&#61;"http://schemas.android.com/apk/res-auto"xmlns:tools&#61;"http://schemas.android.com/tools"><data><variablename&#61;"rating"type&#61;"Float" /></data><LinearLayoutandroid:layout_width&#61;"match_parent"android:layout_height&#61;"match_parent"android:orientation&#61;"vertical"tools:context&#61;".MainActivity"><RatingBarandroid:layout_width&#61;"match_parent"android:layout_height&#61;"wrap_content"android:numStars&#61;"10"android:rating&#61;"&#64;&#61;{rating}"/></LinearLayout>
</layout>

注意使用 &#64;&#61; 表达式。

activity中绑定

final ActivityInverseBindingMethodsBinding binding &#61; DataBindingUtil.setContentView(this,R.layout.activity_inverse_binding_methods);binding.setRating(5f);Log.e("m---->view",binding.getRating()&#43;"");new Handler().postDelayed(new Runnable() {&#64;Overridepublic void run() {Log.e("view---->m",binding.getRating()&#43;"");}},5000);

初始值为5&#xff0c;然后滑动控件&#xff0c;5s后发现控件变化&#xff1a;
在这里插入图片描述


推荐阅读
author-avatar
智慧曜彰_272
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有