新项目使用Databining,已经完整开发一个版本,发现官方的文档以及网上资料都写的不够详细,所以做个整理,对于打算使用Databining的伙伴,应该会很有帮助
我们先回顾下基础用法
定义一个data类,如下
//定义一个用户信息data类
data class UserInfo(var age: Int, var name: String)
非常简单的一个类,在对应的XML中,就可以这样使用DataBinding了
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="data"
type="com.test.data.UserInfo" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.name}"
android:textColor="@color/break_5"
android:textSize="13dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
上面就是DataBinging的最简单用法了,下面结合具体例子,逐渐拓展到其他用法
我想TextView在年龄大于18岁的才展示,小于18岁的不展示,可以这样设置
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{data.name}"
android:visibility="@{(data.age >=18 )?View.VISIBLE:View.GONE}" />
android:textColor="@color/break_5"
android:textSize="13dp" />
年龄大于18岁,textview颜色显示红色
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:textColor="@{(data.age >=18)?@android:color/red:@android:color/white}" />
比如年龄等于30岁,就不显示textview
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{(data.age == 30 )?View.INVISIBLE:View.VISIBLE" />
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:text='@{"姓名:" + data.name}' />
<string name="sales_num">已售%d件</string>
在databinding里面的用法如下<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:text="@{@string/sales_num(data.age)}"
/>
Jack
,就不显示这个TextView,可以这样写<TextView
android:id="@+id/tvStockNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{data.name.equals(`Jack`)?View.INVISIBLE:View.VISIBLE}"
android:text="@{data.name}"/>
class AboutViewModel : ViewModel() {
/**
* 展示注销对话框
*/
fun showLogout(view: View) {
//do something
}
}
然后把这个viewModel传给xml,实现这个点击方法
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.ygp.mro.viewmodels.AboutViewModel" />
</data>
<TextView
android:layout_width="match_parent"
android:layout_height="52dp"
android:text="@string/about_logout_account"
android:onClick="@{viewModel::showLogout}" />
</layout>
这样的话,textview被点击后,会自动调用showLogout方法
我们先定义好这个方法,参数就是View,方法就是关闭当前activity
object BindingHelper {
/**
* 关闭当前activity
*/
@JvmStatic
fun bindFinishActivity(view: View) {
val context = view.context
if (context is FragmentActivity) {
context.finish()
}
}
}
然后在xml的data中import这个类,就可以设置这个onClick事件了
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.ygp.mro.base.common.BindingHelper" />
</data>
<ImageView
android:id="@+id/ivBack"
android:layout_width="44dp"
android:layout_height="44dp"
android:foreground="?attr/selectableItemBackground"
android:onClick="@{BindingHelper::bindFinishActivity}"
android:src="@drawable/icon_arrows_left_large"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</layout>
这样的话,有N个页面,按钮的点击都是关闭当前activity,就可以在XML统一设置,其他地方不需要额外处理
先在viewModel中定义好方法
fun goShopActivity(view: View, name: String) {
//do something
}
这个方法,有一个view参数,还有一个name参数,在xml中,用如下的方式调用
<TextView
android:id="@+id/shopName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="16dp"
android:textColor="@color/break_1"
android:text="@{detail.shopName}"
android:onClick="@{(view)->viewModel.goShopActivity(view,data.name)}"
/>
这样,点击的时候,name参数就也传过去了
/**
* 加载图片
*/
@BindingAdapter("setImageUrl")
@JvmStatic
fun bingImageUrl(imageView: ImageView, imgUrl: String?) {
if (imageView.context.isValid()) {
Glide.with(imageView.context).load(imgUrl ?: "")
.placeholder(glideHolderColor)
.into(imageView)
}
}
然后在XML设置后,就会触发图片加载了
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="imageUrl"
type="String" />
</data>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
app:setImageUrl="@{imageUrl}"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ImageView>
</layout>
我们先定义方法如下
/**
* 加载圆角图片
*/
@BindingAdapter("setImageUrlRound", "setImageRadius")
@JvmStatic
fun bindImageViewUrlRound(imageView: ImageView, url: String?, radius: Int = 8) {
if (imageView.context.isValid()) {
Glide.with(imageView.context)
.load(url)
.placeholder(ColorDrawable(glideHolderColor))
.transform(RoundedCorners(DeviceUtils.dp2px(radius)))
.into(imageView)
}
}
可以发现,BindingAdapter定义了两个属性名称,然后在xml中这样使用
<ImageView
android:id="@+id/ivDetail"
android:layout_width="105dp"
android:layout_height="105dp"
app:setImageRadius="@{5}"
app:setImageUrlRound="@{item.imageUrl}" />
把两个属性分别设置进去,这样加载图片,就可以传多个参数了