zoukankan      html  css  js  c++  java
  • android 数据绑定(6)自定义绑定方法、双向数据绑定

    1.官方文档

      https://developer.android.com/topic/libraries/data-binding/binding-adapters

      https://developer.android.com/topic/libraries/data-binding/two-wa

    2.双向绑定

    2.1 单向的问题

      默认是单向绑定,控件与用户的交互(如输入新的名字,点单选框复选框)不会自动修改对应的绑定数据对象,要在代码里手动处理相应的控件事件,在事件函数里修改数据对象。如:

     1     val data = Data()
     2     lateinit var binding : Way2Binding
     3     val nameWatcher = object : TextWatcher{
     4         override fun afterTextChanged(p0: Editable?) {
     5             val txt = p0.toString()
     6             data.name = txt
     7             binding.invalidateAll()
     8         }
     9         override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    10         override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    11     }
    12 
    13     fun initBinding(){
    14         binding.data = data
    15         binding.normalEdt.addTextChangedListener(nameWatcher)
    16     }

    2.2 使用双向绑定

      使用双向绑定可以简化这个问题,减少相应代码。

      用 @={} 表示可接收属性的数据更改并同时监听用户更新.

    1       <EditText
    2             ...
    3             android:text='@={data.name,default=@string/data_name}'
    4             .../>

      这样当用户在这个EditText上输入新的内容后,直接更新到绑定的数据对象。

      注意: @={} 不可以使用格式化的@string/xx   

    2.3 自定义的属性使用双向绑定

    a.自定义属性的 setXXX 

    1     @BindingAdapter("dataName")
    2     @JvmStatic fun setDataName(edt : EditText, txt : String){
    3         edt.setText(txt)
    4     }

    b.自定义属性的 getXXX

    1     @InverseBindingAdapter(attribute = "dataName")
    2     @JvmStatic fun getDataName(edt : EditText) : String{
    3         return edt.text.toString()
    4     }

    注意:attribute =  不可少,否则编译不过。

    c.编写属性变化监听器及想要监听的事件

     1     @BindingAdapter("dataNameAttrChanged")
     2     @JvmStatic fun setListener(edit : EditText, listener: InverseBindingListener?) {
     3         Log.e("dataNameAttrChanged","txt = ${edit.text.toString()}")
     4         var txt = ""
     5         edit.addTextChangedListener(object : TextWatcher{
     6             override fun afterTextChanged(p0: Editable?) {
     7                 Log.e("dataNameAttrChanged","afterTextChanged")
     8                 if (txt != p0.toString()){
     9                     listener?.onChange()
    10                     txt = p0.toString()
    11                 }
    12             }
    13             override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    14             override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
    15         })
    16     }
    • InverseBindingListener 是属性变化监听器
    • 这个 EditText 监听的事件是 textChanged

    注意:  listener?.onChange() 容易死 循环,要判断下原内容与新内容,不一样才调用这个函数。上述代码中的高亮部分。

    d.布局文件中使用

        <EditText  app:dataName='@={data.name}'  ... >

    2.4 类型转换的双向绑定

    使用类型转换时,也可以使用双向绑定,但是要指定一个反向转换的函数。用 @InverseMethod("转换函数名") 来声明。

     1 @file:JvmName("Converter")
     2 
     3 package com.example.databind
     4 import androidx.databinding.InverseMethod
     5 
     6 
     7 class A (var name: String)
     8 
     9 @InverseMethod("a2String")
    10 fun string2a(string: String) : A{
    11     return A(string)
    12 }
    13 
    14 fun a2String(a : A) : String{
    15     return a.name
    16 }

    在布局文件中

        <EditText android:text='@={Converter.a2String(a)}' />

    2.5 支持双向绑定的内置属性

    控件属性绑定适配器所在的类
    AdapterView android:selectedItemPosition
    android:selection
    AdapterViewBindingAdapter
    CalendarView android:date CalendarViewBindingAdapter
    CompoundButton android:checked CompoundButtonBindingAdapter
    DatePicker android:year
    android:month
    android:day
    DatePickerBindingAdapter
    NumberPicker android:value NumberPickerBindingAdapter
    RadioButton android:checkedButton RadioGroupBindingAdapter
    RatingBar android:rating RatingBarBindingAdapter
    SeekBar android:progress SeekBarBindingAdapter
    TabHost android:currentTab TabHostBindingAdapter
    TextView android:text TextViewBindingAdapter
    TimePicker android:hour
    android:minute
    TimePickerBindingAdapte

    3.自定义绑定

    3.1 系统定义的绑定方法

      假设在绑定布局文件中使用app:aaaaa 的属性,绑定库自动尝试查找方法 setAaaaa(arg)

    • 按app:aaaaa 时传递的参数, 找到参数匹配或兼容的那个方法setAaaaa 
    • 不会考虑属性的命名空间
    • 搜索方法时仅使用属性名称和类型
    • 假设类Student包含 setTtttt 这个方法,那么可以直接在布局文件中使用 app:ttttt 这个属性。

    3.2 自定义绑定的方法

    • a.重新绑定属性与对应的方法
      1     @BindingMethods(value = [
      2     BindingMethod(
      3             type = ImageView::class,
      4             attribute = "android:tint",
      5             method = "setImageTintList")])

     上述代码把 android:tint 这个属性绑定到了setImageTintList方法。官方文档中并没有给出这段应该放哪里,放在类里面编译不过,通过官方完整示例中发现它是全局的。

     

    • b.修改系统已经定义好的方法
       1         @androidx.databinding.BindingAdapter("android:paddingLeft")
       2         @JvmStatic
       3         fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) {
       4             if (oldPadding != newPadding) {
       5                 view.setPadding(12,
       6                         view.getPaddingTop(),
       7                         view.getPaddingRight(),
       8                         view.getPaddingBottom())
       9             }
      10         }

      重新定义了 android:paddingLeft属性,注意,调用的时候  android:paddingLeft='@{16}' 才匹配这个方法,android:paddingLeft="16dp" 还是系统的那个方法。

       出现冲突时,自定义的绑定方法会替换数据绑定库提供的默认方法.

       重新定义系统已经存在的属性没意义,这个方法要以 '@{16}‘ 这种 方式调用,android:paddingLeft="16dp" 无效

    • c.把多个属性联合在一起,绑定个方法
      1         @JvmStatic
      2         @androidx.databinding.BindingAdapter(value = ["imageUrl", "error"], requireAll = false)
      3         fun loadImage(view: ImageView, url: String, error: Drawable) {
      4             Picasso.get().load(url).error(error).into(view)
      5         }

      requireAll = false 的含义是 单独使用imageUrl,error其中一个属性的时候,就绑定这个方法,true就是必需同时使用这两个属性的时候才绑定这个方法。

      使用

      <ImageView
                  android:id="@+id/imageView2"
                  android:layout_width="64dp"
                  android:layout_height="64dp"
                  app:error='@{@drawable/error}'
                  app:imageUrl='@{"sdfsd.com/fef.ppppjnpng"}'
                  />

    3.3 类型转换 @BindingConversion

    作用:使用这个 注解可以定义一个类型A到类型B在转换函数,函数名的格式为

    convertAToB,如 convertStringToData
    1         @JvmStatic
    2         @androidx.databinding.BindingConversion
    3         fun convertStringToData(name : String) = Data()

     

  • 相关阅读:
    (PHP)redis Zset(有序集合 sorted set)操作
    (PHP)redis Set(集合)操作
    (PHP)redis Hash(哈希)操作
    (PHP)redis String(字符串)操作
    (PHP)redis List(列表)操作
    PHP连接 redis
    PHP json 对象 数组互相转换
    循环节长度 蓝桥杯
    三羊献瑞 蓝桥杯
    立方变自身
  • 原文地址:https://www.cnblogs.com/mhbs/p/12059043.html
Copyright © 2011-2022 走看看