DataBinding的使用四

一、前言

本篇主要记录下绑定适配器的用法,下面是一个常见的例子,用于将字符串绑定到android:text属性上面

<?xml version="1.0" encoding="utf-8"?>
<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="value"
            type="String" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/update_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{value}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            tools:text="value" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

假如想要自己对该控件做一些拓展操作的话可以使用绑定适配器功能,绑定适配器既可以对已有的属性做拓展,也可以自定义出新的属性

二、环境配置

如果使用该功能的话需要添加kotlin-kapt拓展

build.gradle

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}

三、拓展功能

1、对现有属性提供自定义逻辑

比如对现有的android:text属性进行拓展

DataBindExtends.kt

@BindingAdapter("android:text")
fun setExtendContent(view: TextView, content: String) {
    view.text = "拓展内容:$content"
}



class DataBindExtends {


}

那么在使用绑定属性更改的值,最终内容都会加上"拓展内容"进行显示

2、修改函数名

根据官网来说是用来修改一些属性具有名称不符的 setter 方法。该方式必须在使用的控件代码基础上进行修改,通常用在自定义控件上(毕竟官方控件TextView之类的也没法修改)。如下

MyTextView.kt

@BindingMethods(value = [
    BindingMethod(
        type = MyTextView::class,
        attribute = "android:text",
        method = "toastContent")])//注意这个函数的参数要和android:text所使用的参数一致
class MyTextView: androidx.appcompat.widget.AppCompatTextView {

    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    )

//    override fun setText(text: CharSequence?) {
//        throw RuntimeException("Stub!")
//    }

    fun toastContent(content: String){
        Toast.makeText(context,content,Toast.LENGTH_SHORT).show()
    }
}

activity_main.xml

     <com.example.myapplication.MyTextView
            android:id="@+id/update_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{change}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:text="value" />

3、自定义多属性适配器

需要注意的是自定义适配器在xml里面必须和数据绑定一起使用

正确写法: app:imageUrl="@{change}"
错误写法: app:imageUrl="asbldbasldas"

DataBindExtends.kt

requireAll = false 表示并非为每一个属性都分配表达式,这样的话有多个属性时候,使用时候不要求全部使用

object DataBindExtends {

    @BindingAdapter(value = ["app:imageUrl", "placeholder"], requireAll = false)
    @JvmStatic fun setImageUrl(imageView: ImageView, url: String?, placeHolder: String) {
        Log.e("YM-->","设置的内容url:$url--->placeHolder:$placeHolder")
    }

    @BindingAdapter("app:popularityIcon")
    @JvmStatic fun popularityIcon(view: ImageView, popularity: String) {

        Log.e("YM-->","--啦啦啦>$popularity")

    }
}
   <ImageView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:imageUrl="@{change}"
            placeholder="@{change}"
            app:popularityIcon="@{change}"/>

4、对旧值的处理

在数据绑定中,允许对一个属性的旧值做一些处理,在一些特殊场景会有一些用处



@BindingAdapter("android:paddingStart")
fun setExtendContent(view: View, content: Int, newContent: Int) {
    Log.e("YM-->","padding设置的内容:oldPadding-->$content--newContent:$newContent")
}
class DataBindExtends {


}
        <View
            android:id="@+id/ads"
            android:layout_width="20dp"
            android:layout_height="100dp"
            android:paddingLeft="@{padding}"
            android:paddingStart="@{padding}"
            android:background="@color/black"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

5、多个监听器的问题

以下来自官方文档

当监听器有多个方法时,必须将它拆分为多个监听器。例如,[View.OnAttachStateChangeListener](https://developer.android.google.cn/reference/android/view/View.OnAttachStateChangeListener) 有两个方法:[onViewAttachedToWindow(View)](https://developer.android.google.cn/reference/android/view/View.OnAttachStateChangeListener#onViewAttachedToWindow(android.view.View))[onViewDetachedFromWindow(View)](https://developer.android.google.cn/reference/android/view/View.OnAttachStateChangeListener#onViewDetachedFromWindow(android.view.View))。该库提供了两个接口,用于区分它们的属性和处理脚本:

    // Translation from provided interfaces in Java:
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    interface OnViewDetachedFromWindow {
        fun onViewDetachedFromWindow(v: View)
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
    interface OnViewAttachedToWindow {
        fun onViewAttachedToWindow(v: View)
    }
    
    @BindingAdapter(
            "android:onViewDetachedFromWindow",
            "android:onViewAttachedToWindow",
            requireAll = false
    )
    fun setListener(view: View, detach: OnViewDetachedFromWindow?, attach: OnViewAttachedToWindow?) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            val newListener: View.OnAttachStateChangeListener?
            newListener = if (detach == null && attach == null) {
                null
            } else {
                object : View.OnAttachStateChangeListener {
                    override fun onViewAttachedToWindow(v: View) {
                        attach.onViewAttachedToWindow(v)
                    }

                    override fun onViewDetachedFromWindow(v: View) {
                        detach.onViewDetachedFromWindow(v)
                    }
                }
            }

            val oldListener: View.OnAttachStateChangeListener? =
                    ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener)
            if (oldListener != null) {
                view.removeOnAttachStateChangeListener(oldListener)
            }
            if (newListener != null) {
                view.addOnAttachStateChangeListener(newListener)
            }
        }
    }
    

6、对象转换

有时候某些属性使用的对象需要进行转换,这里进行演示,以下是每当赋值int类型时候,将转换为 String类型进行返回

<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data >
         <variable
            name="dta"
            type="java.util.Date" />
    </data>

   <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
       
        <TextView
            android:id="@+id/update_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="@{dta}"
            android:paddingStart="10dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            tools:text="value" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
@BindingConversion
fun convertColorToDrawable(color: Date) = "=="


object DataBindExtends {
	 @BindingConversion
    @JvmStatic fun booleanToVisibility(isNotVisible: Boolean): Int {
        return if (isNotVisible) View.GONE else View.VISIBLE
    }
}
}

需要注意的是转换的类型要和xml中使用的类型保持一致。

如果在kotlin里面使用Int之类数据类型的话需要确认其包名,如果使用ObservableInt之类的类型的话,暂时无法生效。

四、参考链接

  1. DataBinding官方示例代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值