美文网首页
DataBinding基本使用(3)

DataBinding基本使用(3)

作者: notrynobug | 来源:发表于2017-09-18 17:18 被阅读0次

    咱们什么都不说 先附上知识点

    • 数据绑定的几种方式
    • 点击事件绑定的几种方式
    • 双向绑定数据
    • RecycleView的数据绑定
    • @InverseMethod 标签的使用
      在DataBinding基本使用(2)中已经讲解了数据绑定的几种方式和点击事件绑定的几种方式,可能本人在某些地方理解偏差或错误,往广大读者指出并一起讨论、学习。

    双向绑定

    请过了摸索和摸坑,总结的来说双向绑定分两种
    1.系统自带属性的双向绑定
    2.自定义属性的双向绑定

    系统自带属性的双向绑定

    首先要注意的是,双向绑定用的符号@={} 而不在是@{}
    既然是系统自带属性的双向绑定,那么我就就不需要在属性的问题上纠结太久,需要修改的是数据源Bean

    public class StudentBean extends BaseObservable {
        private String name = "";
        private int old = 0;
        private boolean studentis = false;
        @Bindable
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
            notifyPropertyChanged(com.example.scs.myapplication.BR.name);
        }
        @Bindable
        public int getOld() {
            return old;
        }
        public void setOld(int old) {
            this.old = old;
            notifyPropertyChanged(com.example.scs.myapplication.BR.old);
        }
        @Bindable
        public boolean isStudentis() {
            return studentis;
        }
        public void setStudentis(boolean studentis) {
            this.studentis = studentis;
            notifyPropertyChanged(com.example.scs.myapplication.BR.studentis);
        }
    }
    

    我们可以看到 在set方法上需要加上@Bindable的注解,在get方法里需要调用notifyPropertyChanged(com.example.scs.myapplication.BR.studentis);可以理解为把参数注册到DataBinding中

    public class BR {
            public static final int _all = 0;
            public static final int changedata = 1;
            public static final int data = 2;
            public static final int main = 3;
            public static final int name = 4;
            public static final int old = 5;
            public static final int studentis = 6;
    }
    

    有的人会说,如果我有还多参数怎么吧?一个个写,一个个改不浪费时间吗?为此
    DataBinding提供了响应式对象:
    针对8种基本类型的数据结构提供了专门的包装类

    • ObservableBoolean
    • ObservableByte
    • ObservableChar
    • ObservableDouble
    • ObservableFloat
    • ObservableInt
    • ObservableLong
    • ObservableShort
      这样就代替了 繁琐的set/get
        public final ObservableField<String> name = new ObservableField<>();
        public final ObservableInt old = new ObservableInt();
        public final ObservableBoolean studemtis = new ObservableBoolean();
    
    

    既然我们已经对数据惊喜了双向的处理,接下来就直接应用数据即可
    既然要证明是双向的,我们多加了一个EditText去修改TextView的内容,看看对应的data是否改变

      <variable
                name="changedata"
                type="com.example.scs.myapplication.StudentBean"></variable>
    
            <variable
                name="main"
                type="com.example.scs.myapplication.Main2Activity"></variable>
      
            <TextView
                android:id="@+id/tv_change"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="@={changedata.name}"
                android:textSize="20dp" />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
    
                <EditText
                    android:id="@+id/et_change"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:layout_weight="1"
                    android:hint="双向绑定--改变view数据" />
    
                <Button
                    android:id="@+id/btn_1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center_vertical"
                    android:onClick="@{main.main2click}"
                    android:text="修改" />
            </LinearLayout>
    

    这边是java代码

    bean = new StudentBean();
    bean.setName("双向绑定--Bean(非自定义)");
    binding.setChangedata(bean);
    binding.setMain(this);
      
    public void main2click(View view) {
            switch (view.getId()) {
                case R.id.btn_1://双向绑定数据 需要 @={}
                    if (!TextUtils.isEmpty(binding.etChange.getText().toString())) {
                        binding.tvChange.setText(binding.etChange.getText().toString());
                        Toast.makeText(view.getContext(), bean.getName(), Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(view.getContext(), "不能为空", Toast.LENGTH_SHORT).show();
                    }
                    break;
                case R.id.btn_2:
                    Intent intent = new Intent(Main2Activity.this, Main3Activity.class);
                    startActivity(intent);
                    break;
            }
        }
    
    

    大家伙儿,都可以去试一试,你们会发现对应的bean的数据也发送了改变。

    bean------->(赋值)TextView
    TextView(修改)------->对应的bean的对应的数据修改

    自定义属性的双向绑定

    一看标题就应该知道,自定义属性,我们需要去处理自定义的数据,和双向的数据。双向的数据的处理方法同上,这里就不在做过多的解释。咱们重点讲解自定义数据如何去实现。
    这里我们需要去理解一下几个属性的含义和使用方法

    • InverseBindingMethods
    • InverseBindingMethod
    • InverseBindingAdapter
    • BindingAdapter

    BindingAdapter

    我们先来讲解一下BindingAdapter,它其实就是用来实现自定义属性所对应的方法

     <variable
                name="tv1data"
                type="String"></variable>
    
      <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:mytext="@{tv1data}"
                android:textSize="30dp" />
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            binding.setTv1data("tv1_data");//加载数据 way1}
    
     @BindingAdapter("android:mytext")
        public static void setMytext(TextView textView, String msg) {
            textView.setText(msg + "");
        }
    

    上述代码就实现了,自定义属性的功能。

    • BindingAdapter 标签可以传两个参数

      1.完整的写法 @BindingAdapter(value = {"android:onItemClick", "android:onLoadMore","android:loadMoreEnable"}, requireAll = false) 其中value当然就是自定义的属性的名字,requireAll表示所有属性是否都要用,true表示都要使用,false表示不用
      2.自定义属性有几种表达形式
      a.android:xxxx @BindingAdapter(“android:xxxx”)
      b.app:xxxx @BindingAdapter(“app:xxxx”)
      c.app:xxxx @BindingAdapter(“xxxx”)
      使用b方法会报错,但是不影响编译

    • 我们首先要定义了一个android:mytext的属性,因为是自定义的属性,所以我们需要提供一个对应的set方法,并且该方法能够起到响应的效果的方法。

    • setMytext方法必须传一个对应控件的对象进去。其次我们在自定义的属性里加了个参数,故在方法中也需要添加对应类别的对象进去。

    • 方法必须要用static修饰

    以上就是自定义属性的使用,举个例子我们可以对Imageview定义个自定义的属性,传入一个url地址,在对应的方法去给Imageview去设置图片

    InverseBindingAdapter

    • InverseBindingAdapter需要传两个参数 attribute:String类型 event: String类型

    1.attribute 必填,表示当值发生变化时,要从哪个属性中检索这个变化的值,示例:"android:text"

    2.event 非必填;如果填写,则使用填写的内容作为event的值;如果不填,在编译时会根据attribute的属性名再加上后缀“AttrChanged”生成一个新的属性作为event的值,举个例子:attribute属性的值为”android:text”,那么默认会在”android:text”后面追加”AttrChanged”字符串,生成”android:textAttrChanged”字符串作为event的值.

    3.event属性的作用: 当View的值发生改变时用来通知dataBinding值已经发生改变了。开发者一般需要使用@BindingAdapter创建对应属性来响应这种改变。
    先上XML代码,因为要实现双向,所以加了输入框去修改数据,来提现双向

    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <data>
            <variable
                name="main"
                type="com.example.scs.myapplication.Main3Activity"></variable>
                    <variable
                        name="data"
                        type="com.example.scs.myapplication.StudentBean"></variable>
                </data>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <com.example.scs.myapplication.MyEditText
                android:id="@+id/my_et"
                android:name="@={data.name}"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
            <Button
                android:id="@+id/btn_1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:onClick="@{main.onMainClick}"
                android:text="修改edittext" />
            <Button
                android:id="@+id/btn_2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:onClick="@{main.onMainClick}"
                android:text="修改bean" />
        </LinearLayout>
    </layout>
    

    java代码

    
    public class Main3Activity extends AppCompatActivity {
        ActivityMain3Binding binding;
        StudentBean bean;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    //        setContentView(R.layout.activity_main3);
            binding = DataBindingUtil.setContentView(this, R.layout.activity_main3);
            binding.setMain(this);
            bean = new StudentBean();
            bean.setName("name");
            binding.setData(bean);
        }
    
        public void onMainClick(View view) {
            switch (view.getId()) {
                case R.id.btn_1:
                    if (!TextUtils.isEmpty(binding.myEt.getText().toString())) {
                        binding.myEt.setName(binding.myEt.getText().toString());
                        Toast.makeText(view.getContext(), bean.getName() + "", Toast.LENGTH_SHORT).show();
                    }
                    break;
                case R.id.btn_2:
                    bean.setName("修改Bean");
                    break;
            }
        }
    }
    

    自定义MyEditText

    public class MyEditText extends android.support.v7.widget.AppCompatEditText {
        private static String name = "";
        @InverseBindingAdapter(attribute = "android:name", event = "android:nameAttrChanged")
        public static String getName(MyEditText editText) {
            return editText.getText().toString();
        }
        @BindingAdapter(value = "android:name", requireAll = false)
        public static void setName(MyEditText editText, String setname) {
            if (setname == null)
                return;
            if (name.equals(setname))
                return;
            name = setname;
            editText.setText(setname + "");
        }
        @BindingAdapter(value = "android:nameAttrChanged")
        public static void setNameListenering(MyEditText editText, final InverseBindingListener listener) {
            if (listener != null) {
                editText.setOnNameListener(new OnNameListener() {
                    @Override
                    public void onName() {
                        listener.onChange();
                    }
                });
            } else {
                editText.setOnNameListener(null);
            }
        }
        public void setName(String name) {
            if (name != null && !name.equals("")) {
                if (onNameListener != null) onNameListener.onName();
            }
        }
        public MyEditText(Context context) {
            super(context);
        }
        public MyEditText(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
        private OnNameListener onNameListener;
        public void setOnNameListener(OnNameListener onNameListener) {
            this.onNameListener = onNameListener;
        }
        public interface OnNameListener {
            void onName();
        }
    }
    

    我们可以看到 使用InverseBindingAdapter,必须要和BindingAdapter相结合使用。
    不说其他,一个自定义的属性,必然要为其提供一个set/get方法。
    我们先来看看InverseBindingAdapter标签 对应的方法就是getXXX对应自定义属性
    提供完了get方法,还需要提供一个set方法,于是乎用BindingAdapter标签来定义一个set方法

    到目前位置,我们似乎还有个变量还没被使用,event对应的属性,之前也说了event的作用就是用来监听自定义属性是否改变。所以我们也需要为event定义一个BindingAdapter属性,setNameListenering方法就是第二个参数就是DataBinding为我们生成的监听.

    大家可以看到为什么还要写个OnNameListener接口,因为InverseBindingListener也需要被调用。

    InverseBindingMethod与InverseBindingMethods

    我们先来看看它们的使用方法
    @InverseBindingMethods({
    @InverseBindingMethod(type = MyEditText.class,attribute = "android:name",event = "android:nameAttrChanged",method = "android:getName")
    })
    说白了 InverseBindingMethod与InverseBindingMethod就是对上面自定义的一个总结

    • type 指的是自定义View的类
    • attribute 就是自定义的属性
    • event 上面已经解释,这里就不在多说
    • method 其实就是对应get方法

    在回顾上面,是不是有属性的get/set方法?这么一看,有众一目了然的感觉

    自定义属性的双向绑定和非自定义属性的双向绑定,就这么讲解完了,若有错误的地方请指出,大家共同进步

    相关文章

      网友评论

          本文标题:DataBinding基本使用(3)

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