DataBinding入门进阶指南(二)

前言

上一篇里,主要讲了关于Databinding的以下几点:

  • 接入与使用
  • 简单的数据绑定
  • 点击事件的绑定

这一篇将会继续上一篇的步伐,对DataBinding的使用更深几分.首先依旧是从数据绑定开始

之前所介绍的,虽然UI与数据进行了绑定,但是修改数据对象的时候并不会同时更新 UI .
现在有三种不同类型的 observable 类:objects, fields, 还有 collections.
当其中某个 observable 数据对象绑定到 UI 并且数据对象的属性发生更改时, UI 将自动更新,下面开始介绍.

Observable数据

如果你的数据类只有几个属性,那么没必要去实现 Observable 接口来监听数据的改变,可以使用下面这些字段:

  • ObservableBoolean
  • ObservableByte
  • ObservableChar
  • ObservableShort
  • ObservableInt
  • ObservableLong
  • ObservableFloat
  • ObservableDouble
  • ObservableParcelable

现在,我们再创建一个类

class ObservableBean {
    val text = ObservableField()
}

布局文件改为:



    
        
    

    

        

        
        
    

需要注意的是,上面的 EditTexttext 属性使用的是 @={}TextView 使用的是 @{} 。当你想要使用双向绑定的时候,可别忘了这个 =

Activity的代码只改变了绑定对象:

class DataBindingActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_data_binding)
        val bindingBinding : ActivityDataBindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding)
        bindingBinding.model = ObservableBean()
    }
}

效果如下:

DataBinding入门进阶指南(二)_第1张图片
image

可以看到,直接使用 Observable 字段去实现双向数据绑定是很轻松的,不过实际项目里面需求各不相同,要将数据都换成 Observable 字段还是很麻烦的,所以自定义双向数据绑定非常有必要!

这时对 ObservableBean 进行修改:

class ObservableBean : BaseObservable() {
    @get:Bindable
    var text: String = ""
    set(value) {
        field = value
        notifyPropertyChanged(BR.text)
    }
}

//相较于Kotlin写法,这里我觉得Java写法更有助于理解:
public  class ObservableBean extends BaseObservable {
    private String text;

    @Bindable
    public String getText() {
        return text;
    }

    public ObservableBean setText(String text) {
        this.text = text;
        notifyPropertyChanged(BR.text);
        return this;
    }
}

修改过后的效果与之前使用 Observable 字段的效果一样,上面需要注意的两点:

  • 使用了 @Bindable 注解,进行绑定声明
  • 使用了 notifyPropertyChanged() 方法为数据刷新做准备

不过在我看来,通过这种继承的方法对于我们原有的数据结构并不过友好,尤其是继承了 BaseObservable 类的数据类不能通过 Gson 去与 Json 相互转换。

所以使用的时候,我们可以考虑通过某个中介类的方式去进行转换.

布局的绑定

第第一篇中,有写到Activity中如何获取自动生成的布局绑定类——xxxBinding,这种类的命名与使用数据绑定的布局文件xml有关,比如说 activity_main.xml 就会生成 ActivityMainBinding

这里再详细说明一下,不同类型的布局,应该怎么获取生成的 Binding绑定类

事先并不知道绑定类型的对象可以使用 DataBindingUtil 去创建绑定

val rootView = LayoutInflater.from(this).inflate(layoutId, parent, attachToParent)
val binding: ViewDataBinding? = DataBindingUtil.bind(viewRoot)

获取带 ID 的 View对象

如果使用的是Kotlin,可以直接在Activity里很方便的使用id获取View对象,不过使用DataBinding后,就有另外一种获取View对象的方式了

布局里面的 Id 如下:

    ...
        

    ...

通过 Id 获取 EditText 的方法如下:

        ...
        super.onCreate(savedInstanceState)
        val bindingBinding : ActivityDataBindingBinding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding)
        bindingBinding.model = ObservableBean()
        val editText = bindingBinding.root.rootView.findViewById(R.id.et_test)

立即绑定

当变量或可观察对象发生更改时,绑定会在下一帧之前更改。 不过有的时候需要立刻执行绑定.

若要强制执行,可以使用 executePendingBindings() 方法。

高级绑定

有时候,特定的绑定类是未知的.

例如,针对任意布局操作的 RecyclerView.Adapter 不知道特定的绑定类.它仍然必须在调用 onBindViewHolder() 方法时分配绑定值.

RecyclerViewonBindViewHolder() 方法里,可以这样写:

override fun onBindViewHolder(holder: BindingHolder, position: Int) {
    item: T = mItems.get(position)
    holder.binding.setVariable(BR.item, item);
    holder.binding.executePendingBindings();
}

使用@BindingAdapter自定义绑定逻辑

DataBinding为我们提供了一种可以对绑定逻辑进行自定义的方法,比如说我想在xml中对一个ImageView控件加载图片,并且是使用的Glide加载框架,这时候可以这样:

//随便创建一个类,然后在类中定义如下方法
@BindingAdapter("imageUrl")
fun loadImage(view: ImageView, url: String) {
    GlideApp.with(view.getContext())
   .load(url)
   .fitCenter()
   .into(view);
}

使用的时候编译器会自动生成对应属性:


使用 @BindAdapter 几乎可以完成你想要的各种逻辑,不过我觉得,只有那种使用率特别高的代码,才最适合这个属性.

使用@BindingConversion完成转换功能

在某些情况下,特定类型之间需要自定义转换。 例如,视图的android:background属性需要Drawable,但指定的颜色值是整数。

官方例子中,转换功能的具体用法如下:

@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)

使用的时候可以这样:


暂歇

本篇关于DataBindin的介绍也就到此结束,不过DataBinding的使用还没有到头,下一篇将会侧重实际上的操作以及DataBinding还可以为我们带来哪些便捷.


未完待续

你可能感兴趣的:(DataBinding入门进阶指南(二))