dataBinding
数据的双向绑定,使用dataBinding,在xml布局文件中·对指定的布局内容设置,当数据内容发生改变,自动更新到xml上,这配合LiveData使用。另外可以编写顶层函数,顶部增加@BindAdapter注解。
/**
* A Binding Adapter that is called whenever the value of the attribute `android:progressTint`
* changes. Depending on the value it determines the color of the progress bar.
*/
@BindingAdapter("app:progressTint")
fun tintPopularity(view: ProgressBar, popularity: Popularity) {
val color = getAssociatedColor(popularity, view.context)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.progressTintList = ColorStateList.valueOf(color)
}
}
比如上面这样,表示监听progressBar,当progressBar设置了app:progressTint属性时启动,会根据popularity的内容改变时发生调用。这就实现了用户点击的响应。
代码实验室地址:https://developer.android.com/codelabs/android-databinding#0
大致步骤:
1、在build.gradle文件夹中启动databinding
android {
...
dataBinding {
enabled true
}
}
2、将布局文件转换为layout做为根节点。同时在data节点中增加相关变量。
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.example.android.databinding.basicsample.data.SimpleViewModelSolution"/>
</data>
....
</layout>
3、然后就可以对具体的控件设置内容,比如
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
// Bind the name property of the viewmodel to the text attribute
android:text="@{viewmodel.name}"
// Bind the nameVisible property of the viewmodel to the visibility attribute
android:visibility="@{viewmodel.nameVisible}"
// Call the onLike() method on the viewmodel when the View is clicked.
android:onClick="@{() -> viewmodel.onLike()}"
//当然也可以自定义一些简单的值
<data>
<variable name="name" type="String"/>
<variable name="lastName" type="String"/>
</data>
<TextView
android:id="@+id/plain_name"
android:text="@{name}"
... />
4、修改完xml布局布局文件,现在开始修改kt文件。原先的setContentView方法换一种方式
val binding : PlainActivityBinding =
DataBindingUtil.setContentView(this, R.layout.plain_activity)
结合上面那段代码,利用获取到的binding对象设置在xml文件中申明的那边变量、对象的具体值
binding.viewModel = viewModel
//下面这个是因为viewmodel中使用了liveData,liveData是可观察的数据,会在对应的页面生命周期可见的情况下更新视图,这就需要明确的指定到底是谁的生命周期了
binding.lifecycleOwner = this
到这里初步的数据自动更新到ui上就ok了。
下面开始设置绑定适配器
//单个属性
@BindingAdapter("app:hideIfZero")
fun hideIfZero(view: View, number: Int) {
view.visibility = if (number == 0) View.GONE else View.VISIBLE
}
//使用时就是下面这样
<ProgressBar
android:id="@+id/progressBar"
app:hideIfZero="@{viewmodel.likes}"
...
这个绑定适配器:应用于app:hideIfZero属性。可以应用到每个视图(因为第一个参数是一个视图;您可以通过更改此类型来限制为某些类)接受一个整数,该整数应该是布局表达式返回的结果。如果数字为0,则视图消失。否则可见。
多个属性
@BindingAdapter(value = ["app:progressScaled", "android:max"], requireAll = true)
fun setProgress(progressBar: ProgressBar, likes: Int, max: Int) {
progressBar.progress = (likes * max / 5).coerceAtMost(max)
}
如果缺少任何属性,则不使用此绑定适配器。这发生在编译时。该方法现在接受3个参数(它所应用的视图加上注释中定义的属性数量)。requireAll参数定义了何时使用绑定适配器:当为true时,所有元素都必须出现在XML定义中。如果为false,则缺失的属性将为null,如果为布尔值则为false,如果为原语则为0。