
BindingAdapter 是 DataBinding 数据绑定技术 的组成部分 ;
借助 @BindingAdapter 注解 可以 将自定义逻辑 绑定到 DataBinding 布局中 ;
在 DataBinding 布局中 , 不只是机械性的显示内容 或者 拼接内容 , 还需要 进行更复杂的操作 ;
如 : 为 ImageView 组件绑定数据模型 , 传入一个 url 网络图片地址 , 在该组件中显示网络图片 , 如果网络图片加载失败或者为空 , 则加载默认的本地资源 ;
上述操作必须 自定义一段代码逻辑进行实现 , 使用简单的数据绑定无法实现该功能 ;
首先 , 启用 DataBinding , 在 DataBinding 数据绑定 布局中 引入 绑定的数据模型 ;
<data>
<variable
name="变量名"
type="变量类型" />
</data>然后 , 在 DataBinding 布局中 , 为组件的 app:注解参数 属性设置 "@{变量名}" 属性值 ; 该属性名称 注解参数 就是使用 @BindingAdapter("注解参数") 注解修饰的 Java 静态函数 ;
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:注解参数="@{变量名}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"/>最后 , 定义 BindingAdapter 静态方法 , 该静态方法使用 @BindingAdapter 注解修饰 , 方法的参数就是 @{变量名} 类型的参数 ;
@JvmStatic
@BindingAdapter("注解参数")
fun setImage(组件参数名称: 组件类型, 绑定变量名: 变量类型) {
// 绑定的代码逻辑
}注解参数 与 DataBinding 布局中的组件 app:注解参数 属性名称 对应 ;
DataBinding 布局中的 变量名 与 组件 app:注解参数 属性值 对应 ;
在 DataBinding 布局中 , 绑定数据模型 ;
<data>
<variable
name="imageNetwork"
type="String" />
</data>在 ImageView 组件中 , 设置 app:image="@{imageNetwork}" 属性 , imageNetwork 是绑定的数据 ;
app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageNetwork}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"/>在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;
使用 @BindingAdapter("image") 修饰函数 , 其中的注解参数 image 对应组件中的 app:image 属性 ;
imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;
url: String 参数是 DataBinding 布局中绑定的数据模型 ;
class ImageViewBindingAdapter {
companion object {
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- url: String 参数是 ImageView 的 app:image 属性值
- app:image="@{imageNetwork}"
- imageUrl 该值是 <data> 标签中的 variable , 类型为 String
<data>
<variable
name="imageNetwork"
type="String" />
</data>
*/
@JvmStatic
@BindingAdapter("image")
fun setImage(imageView: ImageView, url: String) {
// 加载网络图片
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).into(imageView);
} else {
imageView.setBackgroundColor(Color.GREEN)
}
}
}
}在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;
// 设置布局文件
// 布局文件是 activity_main.xml
// 该类名称生成规则是 布局文件名称 + Binding
var activityMainBinding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
// 为布局 设置 数据
activityMainBinding.imageNetwork = "https://img-blog.csdnimg.cn/0d611b315e8448f7a01f7a772c238c6f.png"在 DataBinding 布局中 , 绑定数据模型 ;
<data>
<variable
name="imageLocal"
type="int" />
</data>在 ImageView 组件中 , 设置 app:image="@{imageLocal}" 属性 , imageLocal 是绑定的数据 ;
app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;
<ImageView
android:id="@+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageLocal}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4"/>在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;
使用 @BindingAdapter("image") 修饰函数 , 其中的注解参数 image 对应组件中的 app:image 属性 ;
imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;
resourceId: Int 参数是 DataBinding 布局中绑定的数据模型 ;
class ImageViewBindingAdapter {
companion object {
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- resourceId: Int 参数是 ImageView 的 app:image 属性值
- app:image="@{imageLocal}"
- imageLocal 该值是 <data> 标签中的 variable , 类型为 int
<data>
<variable
name="imageLocal"
type="int" />
</data>
*/
@JvmStatic
@BindingAdapter("image")
fun setImage(imageView: ImageView, resourceId: Int) {
imageView.setImageResource(resourceId)
}
}
}在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;
// 设置布局文件
// 布局文件是 activity_main.xml
// 该类名称生成规则是 布局文件名称 + Binding
var activityMainBinding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
// 为布局 设置 数据
activityMainBinding.imageLocal = R.mipmap.ic_launcher在 DataBinding 布局中 , 绑定数据模型 ;
<data>
<variable
name="imageNetwork"
type="String" />
<variable
name="imageLocal"
type="int" />
</data>在 ImageView 组件中 ,
设置 app:image="@{imageNetwork}" 属性 , imageNetwork 是绑定的数据 ;
设置 app:imageDefaultRes="@{imageLocal}"" 属性 , imageLocal 是绑定的数据 ;
app:image 属性 , 对应着 @BindingAdapter("image") 注解中的 注解参数 image ;
<ImageView
android:id="@+id/imageView3"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageNetwork}"
app:imageDefaultRes="@{imageLocal}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"/>在 Kotlin 中 , 定义 Java 静态方法 , 需要在 companion object 伴生对象 中 , 使用 @JvmStatic 修饰函数 ;
使用 @BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false) 修饰函数 ,
value = ["image", "imageDefaultRes"] 对应组件中的 app:image 和 app:imageDefaultRes"属性 ;requireAll = false 表示这两个注解属性 , 不是必须都齐全的 , 可以设置任意一个 , 也可以都设置 ;imageView: ImageView 参数是 DataBinding 布局中的 被绑定的组件 ;
url: String 参数是 DataBinding 布局中绑定的数据模型 ;
<variable
name="imageNetwork"
type="String" />resourceId: Int 参数是 DataBinding 布局中绑定的数据模型 ;
<variable
name="imageLocal"
type="int" />class ImageViewBindingAdapter {
companion object {
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- url: String 参数是 ImageView 的 app:image 属性值
- app:image="@{imageNetwork}"
- imageUrl 该值是 <data> 标签中的 variable , 类型为 String
- resourceId: Int 参数是 ImageView 的 app:image 属性值
- app:image="@{imageLocal}"
- imageLocal 该值是 <data> 标签中的 variable , 类型为 int
<data>
<variable
name="imageNetwork"
type="String" />
<variable
name="imageLocal"
type="int" />
</data>
注意 : 如果是 Java 静态函数 , 注解为
@BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
Kotlin 中使用 [] 初始化数组 , Java 中使用 {} 初始化数组
*/
@JvmStatic
@BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
fun setImage(imageView: ImageView, url: String, resourceId: Int) {
// 加载网络图片
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).into(imageView);
} else {
imageView.setImageResource(resourceId)
}
}
}
}在 Activity 组件中 , 向 DataBinding 布局中设置 imageNetwork 数据模型的对象 ;
// 设置布局文件
// 布局文件是 activity_main.xml
// 该类名称生成规则是 布局文件名称 + Binding
var activityMainBinding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
// 为布局 设置 数据
activityMainBinding.imageLocal = R.mipmap.ic_launcherplugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
namespace 'kim.hsl.databinding_demo'
compileSdk 32
defaultConfig {
applicationId "kim.hsl.databinding_demo"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// 启用 DataBinding
dataBinding {
enabled = true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '9'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation 'com.squareup.picasso:picasso:2.71828'
}<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DataBinding_Demo"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest><?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="imageNetwork"
type="String" />
<variable
name="imageLocal"
type="int" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageNetwork}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"/>
<ImageView
android:id="@+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageLocal}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4"/>
<ImageView
android:id="@+id/imageView3"
android:layout_width="100dp"
android:layout_height="100dp"
app:image="@{imageNetwork}"
app:imageDefaultRes="@{imageLocal}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>package kim.hsl.databinding_demo
import android.graphics.Color
import android.text.TextUtils
import android.widget.ImageView
import androidx.databinding.BindingAdapter
import com.squareup.picasso.Picasso
class ImageViewBindingAdapter {
companion object{
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- url: String 参数是 ImageView 的 app:image 属性值
- app:image="@{imageNetwork}"
- imageUrl 该值是 <data> 标签中的 variable , 类型为 String
<data>
<variable
name="imageNetwork"
type="String" />
</data>
*/
@JvmStatic
@BindingAdapter("image")
fun setImage(imageView: ImageView, url: String) {
// 加载网络图片
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).into(imageView);
} else {
imageView.setBackgroundColor(Color.GREEN)
}
}
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- resourceId: Int 参数是 ImageView 的 app:image 属性值
- app:image="@{imageLocal}"
- imageLocal 该值是 <data> 标签中的 variable , 类型为 int
<data>
<variable
name="imageLocal"
type="int" />
</data>
*/
@JvmStatic
@BindingAdapter("image")
fun setImage(imageView: ImageView, resourceId: Int) {
imageView.setImageResource(resourceId)
}
/*
DataBinding 布局中 ImageView 适配器
- imageView: ImageView 参数就是布局中的 ImageView
- url: String 参数是 ImageView 的 app:image 属性值
- app:image="@{imageNetwork}"
- imageUrl 该值是 <data> 标签中的 variable , 类型为 String
- resourceId: Int 参数是 ImageView 的 app:image 属性值
- app:image="@{imageLocal}"
- imageLocal 该值是 <data> 标签中的 variable , 类型为 int
<data>
<variable
name="imageNetwork"
type="String" />
<variable
name="imageLocal"
type="int" />
</data>
注意 : 如果是 Java 静态函数 , 注解为
@BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
Kotlin 中使用 [] 初始化数组 , Java 中使用 {} 初始化数组
*/
@JvmStatic
@BindingAdapter(value = ["image", "imageDefaultRes"], requireAll = false)
fun setImage(imageView: ImageView, url: String, resourceId: Int) {
// 加载网络图片
if (!TextUtils.isEmpty(url)) {
Picasso.get().load(url).into(imageView);
} else {
imageView.setImageResource(resourceId)
}
}
}
}package kim.hsl.databinding_demo
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import kim.hsl.databinding_demo.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 设置布局文件
// 布局文件是 activity_main.xml
// 该类名称生成规则是 布局文件名称 + Binding
var activityMainBinding: ActivityMainBinding =
DataBindingUtil.setContentView(this, R.layout.activity_main)
// 为布局 设置 数据
activityMainBinding.imageNetwork = "https://img-blog.csdnimg.cn/0d611b315e8448f7a01f7a772c238c6f.png"
activityMainBinding.imageLocal = R.mipmap.ic_launcher
}
}
本篇博客加载的图片 :
