RecyclerView(6) 搭配使用 DataBinding

2022-12-07  本文已影响0人  行走中的3卡

目的是:设置数据绑定,并消除对 findViewById() 的调用

和前面系列文章一样, 关注 DataBinding /BindingAdapter 在RecyclerView 上的使用思想, 忽略具体的代码细节.

1.向布局文件 添加 数据绑定

(1)在 Code 标签页中打开 list_item_sleep_night.xml 布局文件。
将光标放在 ConstraintLayout 标签上,然后按 Alt+Enter
系统随即会打开 intent 菜单(“quick fix”菜单)。
(2)选择 Convert to data binding layout。这会将布局封装到 <layout> 中,并在其中添加 <data> 标签。
(3)根据需要滚动回顶部,并在 <data> 标签内声明一个名为 sleep 的变量。
(4)将其 type 设为 SleepNight 的完全限定名称
com.example.android.trackmysleepquality.database.SleepNight。
完成后的 <data> 标签应如下所示:

<layout
   <data>
        <variable
            name="sleep"
            type="com.example.android.trackmysleepquality.database.SleepNight"/>
    </data>
</layout>   

可见,加了一层 父布局 <layout>

(5) 如需强制创建 Binding 对象,请依次选择 Build > Clean Project,
然后依次选择 Build > Rebuild Project。
(如果仍然存在问题,请依次选择 File > Invalidate Caches / Restart。)
ListItemSleepNightBinding 绑定对象以及相关代码会添加到项目生成的文件中。

2. 第 2 步:使用 数据绑定 加载 项布局

SleepNightAdapter 的ViewHolder 中,
删除:

val view = layoutInflater
       .inflate(R.layout.list_item_sleep_night, parent, false)

增加:

val binding =
ListItemSleepNightBinding.inflate(layoutInflater, parent, false)

修改:

return ViewHolder(binding) // 参数为 ListItemSleepNightBinding

//参数为 ListItemSleepNightBinding 且 binding.root 为根View (例子中的ConstraintLayout)
lass ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root){

此外, ViewHolder 中的自定的变量也可删掉,使用binding.xxx.

至此, 使用了DataBinding 取代了 findViewById 的操作,
通过 布局对应的 Binding 类, 直接获取到 控件.

例如:
android:id="@+id/quality_string" ====> binding.qualityString
注意: 会把下划线去掉, 变成驼峰式变量名

3. 创建 绑定适配器 BindingAdapter

绑定适配器 会获取数据特别是复杂的,
并将其调整为可供数据绑定功能用于绑定视图(例如文本或图片)的内容

实现三个绑定适配器,一个用于高质量图片,另外两个分别用于一个文本字段

要定义一种获取项和视图的方法,并用 @BindingAdapter 进行注解

在 Kotlin 中,可以在接收数据的视图类上将 绑定适配器编写为 扩展函数

3.1 创建 BindingAdapter 声明的函数

其实这里就是为了 将 SleepNight 数据, 转换成 能够在 View 上显示的数据(文本、图片)
创建 BindingUtils.kt, 用于创建 静态函数

class BindingUtils {}

(1) 睡眠时间 sleepDurationFormatted
在 TextView 上声明一个名为 setSleepDurationFormatted 的扩展函数
将数据绑定到视图,如在 ViewHolder.bind() 中一样.
请使用 @BindingAdapter 为该函数添加注解, 向数据绑定功能告知此绑定适配器.

@BindingAdapter("sleepDurationFormatted")
fun TextView.setSleepDurationFormatted(item: SleepNight) {
   text = convertDurationToFormatted(item.startTimeMilli, item.endTimeMilli, context.resources)
}

(2) 睡眠质量 sleepQualityString

@BindingAdapter("sleepQualityString")
fun TextView.setSleepQualityString(item: SleepNight) {
   text = convertNumericQualityToString(item.sleepQuality, context.resources)
}

(3)sleepImage

@BindingAdapter("sleepImage")
fun ImageView.setSleepImage(item: SleepNight) {
   setImageResource(when (item.sleepQuality) {
       0 -> R.drawable.ic_sleep_0
       1 -> R.drawable.ic_sleep_1
       2 -> R.drawable.ic_sleep_2
       3 -> R.drawable.ic_sleep_3
       4 -> R.drawable.ic_sleep_4
       5 -> R.drawable.ic_sleep_5
       else -> R.drawable.ic_sleep_active
   })
}

这个相对简单了.

3.2 在ViewHolder 中为 布局文件 设置 数据类对象.

    class ViewHolder private constructor(val binding: ListItemSleepNightBinding) : RecyclerView.ViewHolder(binding.root) {

        fun bind(
            item: SleepNight
        ) {
            binding.sleep = item
            // 此调用是一种优化,用于要求数据绑定功能立即执行任何待处理的绑定
            // 当您在 RecyclerView 中使用绑定适配器时,最好调用 executePendingBindings(),因为它可以略微加快调整视图大小的过程
            binding.executePendingBindings()
/*     // 可以使用 Databinding 和 BindingAdapter 执行
            val res = itemView.context.resources
            binding.sleepLength //取代  viewHolder.findViewById(R.id.sleep_length)
                .text = convertDurationToFormatted(
                item.startTimeMilli, item.endTimeMilli, res
            )

            binding.qualityString.text = convertNumericQualityToString(item.sleepQuality, res)
            binding.qualityImage.setImageResource(
                when (item.sleepQuality) {
                    0 -> R.drawable.ic_sleep_0
                    1 -> R.drawable.ic_sleep_1
                    2 -> R.drawable.ic_sleep_2
                    3 -> R.drawable.ic_sleep_3
                    4 -> R.drawable.ic_sleep_4
                    5 -> R.drawable.ic_sleep_5
                    else -> R.drawable.ic_sleep_active
                }
            )
 */
        }

注意: 需要在 类的顶级, 即在类体外部

3.3 向 XML 布局添加绑定

为文本、图片View 添加 绑定 (数据类)
因为 3.1 中创建的 BindingAdapter 函数 都需要一个参数 SleepNight(这里是sleep对象)

app:sleepImage="@{sleep}"

app:sleepDurationFormatted="@{sleep}"

app:sleepQualityString="@{sleep}"

至此,已完成所有.

参考文献:
https://developer.android.com/codelabs/kotlin-android-training-diffutil-databinding?hl=zh-cn#6
完整代码:
https://github.com/google-developer-training/android-kotlin-fundamentals-apps/tree/master/RecyclerViewDiffUtilDataBinding

上一篇下一篇

猜你喜欢

热点阅读