前面的三篇文章主要是讲了如何将数据和UI界面绑定,通过这种技术可以轻松解决数据更新到UI界面,减少Activity代码量。但是,之前的技术只能在View内置的已有属性上使用,比如setText和getText。如果你需要在自定义的属性上以及View的内置属性上进行扩展,你就需要使用
@BindingAdapter
接下来,我将用Glide+@BindingAdapter来完成一个下载图片的小功能
自定义属性:
首先自定义一个属性来加载图片,自定义属性的类:
class ImageLoader {
companion object{
@JvmStatic
@BindingAdapter(value = ["loadImage"])
fun loadImage(imageView: ImageView, loadUrl:String){
Glide.with(imageView)
.load(loadUrl)
.into(imageView)
从上面代码可以看到:
- 要实现自定义属性加载图片需要用到
@BindingAdapter注解,通过value设置自定义属性的名称,同时value的值决定UI界面的自定义属性的名称,比如UI界面中就是app:loadImage。 - value是一个字符串数组,可以接受多个参数。如果这里是用kotlin编写的,所以用
[]取代Java的{}。(注意:这里如果是Java用{})。 - loadImage必须是一个
public static的方法,在kotlin中如何表示呢?如同上面代码所示,你需要加上@JvmStatic同时在companion object伴生对象中。事实上,如果你反编译成Java后是这样的public static final void loadImage(){}。 - 第一个参数必须是需要自定义属性的那个View,比如这里是ImageView。事实上,我的需求是在ImageView上新增一个能加载网络图片的属性,所以这里的第一个参数就是ImageView。同理,如果你想在TextView上扩展一个属性,那么第一个参数肯定就是TextView。
<?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">
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/show_image"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="5dp"
app:loadImage="@{`https://cn.bing.com/sa/simg/hpb/LaDigue_EN-CA1115245085_1920x1080.jpg`}"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
这里的写法和之前有点不一样,之前由于需要和数据绑定,<data></data>里面会有需要加载的数据。这里不需要绑定额外额数据,所以只需要<data></data>即可。
Activity:
class LoadImageActivity:AppCompatActivity() {
var binding:ActivityLoadImageBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_load_image)
这里更加简单,通过DataBindingUtil.setContentView绑定下UI界面就行了。
在实际的开发中,加载图片中间会一般先展示占位图,加载错误会有错误显示图。那么这些属性如何能同时展示在ImageView上呢?上面提到@BindingAdapter的value是一个字符串数组,那么我们就可以利用这个来解决展示多个属性的问题。
kotlin代码:
class ImageLoader {
companion object{
@JvmStatic
@BindingAdapter(value = ["placeHolder", "error", "loadImage"])
fun loadImage(imageView: ImageView, placeHolder:Drawable, error:Drawable, loadUrl:String){
Glide.with(imageView)
.load(loadUrl)
.apply(RequestOptions().placeholder(placeHolder).error(error))
.into(imageView)
@JvmStatic
@BindingAdapter(value = ["placeHolder", "error", "loadImage"], requireAll = false)
fun loadImage(imageView: ImageView, placeHolder:Drawable?, error:Drawable?, loadUrl:String?){
Glide.with(imageView)
.load(loadUrl)
.apply(RequestOptions().placeholder(placeHolder).error(error))
.into(imageView)
以上代码在编译的时候需要有以下几点需要注意:
- 这里需要注意value数组的"属性名称"的顺序一定要和参数的顺序一一对应上,要不然会出现编译错误的问题。
- @BindingAdapter有个参数"requireAll",如果设置为true(默认是true),那么以上的三个属性必须全部都要使用在UI界面上,如果设置为false,那么就不需要三个属性必须全部都要使用。
- 注意上面的除了imageView参数都需要加上"空字符串安全符"具体原因可以参考这篇文章记录bug:Kotlin+@BindingAdapter的一个bug
通过@BindingAdapter可以实现自定义属性和数据的绑定,同时实现数据更新可以直接体现到UI界面上(单向绑定)。那么,既然有单向绑定,比如也会有自定义属性的双向绑定,下一篇文章,将实现自定义属性的双向绑定。
写在前面:关于DataBinding,感觉用的人不是很多,毕竟这是一个服务于XML的,如果要是单纯的用来绑定控件,用ViewBinding或者Kotlin的Kotlin-android-extension也都够用了。上网查了查,也有很多关于DataBinding坑很大的说法,这里贴一篇郭神的文章来解个惑。
犹豫要不要用DataBinding?这篇文章帮你解惑
关于DataBinding的用法资料一堆,这篇文章主要说的是自定义BindingAdapter的创建与使用。
通过观察源码不难发现,自动生成的View
中文版 README
Free from writing adapters! NO MORE CLASSES!
Super simple RecyclerView adapter using Data Binding Technology, no longer need to write any adapter!
You don't need to write any extra class like ViewHolder or ItemView.
One more reason you should try Data Binding!
Get Started
dependencies {
compile 'com.github.markzhai:databinding-rv-adapter:1.0.1'
This library provide two types of RecyclerView.Adapter.
SingleTypeAdapter:
SingleTypeAdapter adapter = n
本文主要介绍DataBinding在Android App中的使用方法。数据绑定是将“提供器”的数据源与“消费者”绑定并使其同步的一种通用技术。
1. Android应用程序使用数据绑定
1.1 介绍DataBinding
Android通过DataBinding提供了编写声明型布局的支持。这样可以最大程度简化布局和逻辑相关联的代码。
数据绑定要求修改文件,外层需要包裹一个layout布局。主要通过@{} 或 @={}语法把布局中的元素和表达式的引用写入到属性中。
<?xml version="1.
2.1 Data——FakeData
2.2 View——fragment_plant_detail.xml
2.3 ViewDataBinding——FragmentPlantDetailBinding
2.4 adapter 绑定说明
3 免 find
@BindingAdapter("imageFromUrl")
fun bindImageFromUrl(view: ImageView, imageUrl: String?) {
if (!imageUrl.isNullOrEmpty()) {
Glide.with(view.context)
.load(imageUrl)
.transition(DrawableTransitionOpti..
2、使用 @BindingAdapter 注解为布局组件绑定自定义逻辑
二、使用 @BindingAdapter 注解绑定加载网络图片静态方法
三、使用 @BindingAdapter 注解绑定加载本地图片静态方法
四、使用 @BindingAdapter 注解绑定加载网络图片或本地图片静态方法
五、完整代码示例
1、build.gradle 构建脚本
2、AndroidManifest.xml 清单文件
3、DataBinding 布局文件
@JvmStatic
@BindingAdapter("imageurl")
fun loadImage(imageView: ImageView, url: String) {
Glide.wit...