新项目使用Databining,已经完整开发一个版本,发现官方的文档以及网上资料都写的不够详细,所以做个整理,对于打算使用Databining的伙伴,应该会很有帮助
基础使用
我们先回顾下基础用法
定义一个data类,如下
代码语言:javascript复制//定义一个用户信息data类
data class UserInfo(var age: Int, var name: String)
非常简单的一个类,在对应的XML中,就可以这样使用DataBinding了
代码语言:javascript复制<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岁的不展示,可以这样设置
代码语言:javascript复制<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颜色显示红色
代码语言:javascript复制<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
代码语言:javascript复制<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}' />
- 字符串本身有带有%d和%s的占位符
比如这个string
<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)}"
/>
- 在XML中对比字符串做条件判断
比如name的值为
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}"/>
点击事件
- 常规的方式 外部传一个实现click方法的类 定一个viewModel,实现click方法:showLogout,方法参数就一个,就是view
class AboutViewModel : ViewModel() {
/**
* 展示注销对话框
*/
fun showLogout(view: View) {
//do something
}
}
然后把这个viewModel传给xml,实现这个点击方法
代码语言:javascript复制<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方法
- 通用的点击方法 有个点击方法,很多页面都在使用,比如我们的titleBar,有个返回按钮,点击后,都是关闭当前页面
我们先定义好这个方法,参数就是View,方法就是关闭当前activity
代码语言:javascript复制object BindingHelper {
/**
* 关闭当前activity
*/
@JvmStatic
fun bindFinishActivity(view: View) {
val context = view.context
if (context is FragmentActivity) {
context.finish()
}
}
}
然后在xml的data中import这个类,就可以设置这个onClick事件了
代码语言:javascript复制<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统一设置,其他地方不需要额外处理
- 点击事件带参数 上面的DataBinding事件,都是只有一个View参数,有些场景,方法需要更多的参数,可以这样设置
先在viewModel中定义好方法
代码语言:javascript复制fun goShopActivity(view: View, name: String) {
//do something
}
这个方法,有一个view参数,还有一个name参数,在xml中,用如下的方式调用
代码语言:javascript复制<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设置后,就会触发图片加载了
代码语言:javascript复制<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>
- 多个参数的方法 还是图片加载,需要传圆角参数,不同的地方,圆角的弧度可以自定义设置
我们先定义方法如下
代码语言:javascript复制/**
* 加载圆角图片
*/
@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中这样使用
代码语言:javascript复制<ImageView
android:id="@ id/ivDetail"
android:layout_width="105dp"
android:layout_height="105dp"
app:setImageRadius="@{5}"
app:setImageUrlRound="@{item.imageUrl}" />
把两个属性分别设置进去,这样加载图片,就可以传多个参数了