Android DataBinding 自定义View实现数据双向绑定

看不懂的可以先看看单向数据绑定:Android DataBinding数据变化时自动更新界面_皮皮高的博客-CSDN博客

然后再确定已经启动了dataBinding的情况下,按下面的顺序来:

首先创建一个自定义View:

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View

class MyView(context: Context, attr: AttributeSet) : View(context, attr) {

    var number = 0
        set(value) {
            field = value
            invalidate()
        }

    private val onNumberChangeListenerList = ArrayList<OnNumberChangeListener>()

    private val paint = Paint()

    init {
        setOnClickListener {
            number ++
            invalidate()
            for (item in onNumberChangeListenerList) {
                item.onChange(number)
            }
        }
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        canvas!!
        paint.color = Color.RED
        canvas.drawRect(Rect(0, 0, width, height), paint)
        paint.color = Color.YELLOW
        paint.textSize = resources.displayMetrics.density * 20
        canvas.drawText(number.toString(), width  / 2f, height / 2f, paint)
    }

    fun addOnNumberChangeListener(listener: OnNumberChangeListener) {
        onNumberChangeListenerList.add(listener)
    }

    fun removeOnNumberChangeListener(listener: OnNumberChangeListener) {
        onNumberChangeListenerList.remove(listener)
    }

    interface OnNumberChangeListener {
        fun onChange(number: Int)
    }

}

代码很简单,就是在界面上显示一个矩形,然后里面有个文本,用来显示被点击了多少次。

接着实现双向数据绑定逻辑:

import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
import androidx.databinding.adapters.ListenerUtil

object ViewAdapter {

    @BindingAdapter("number")
    @JvmStatic fun setNumber(view: MyView, number: Int){
        if (view.number == number) {
            return
        }
        view.number = number
    }

    @InverseBindingAdapter(attribute = "number")
    @JvmStatic fun getNumber(view: MyView): Int{
        return view.number
    }

    @BindingAdapter("numberAttrChanged")
    @JvmStatic fun setNumberListener(view : MyView, listener: InverseBindingListener?) {
        val newListener = object : MyView.OnNumberChangeListener {
            override fun onChange(number: Int) {
                listener?.onChange()
            }
        }
        val oldListener = ListenerUtil.trackListener(view, newListener, R.id.onNumberChangeListener)
        oldListener?.apply {
            view.removeOnNumberChangeListener(this)
        }
        view.addOnNumberChangeListener(newListener)
    }

}

总的来说只要实现三个方法就行了,现在来说下每个方法的含义:

setNumber() 用于把数据设置到View上,这里还需要添加判断数据是否重复,重复了就return,不然有概率会死循环
getNumber() 用于给框架提供数据,也就是要返回用于数据双向绑定的值。
setNumberListener() 用于给框架设置数据变化监听,当监听到变化时,框架就会调用getNumber()来获取数据并应用到ViewMode上。(方法内部调用了一个ListenerUtil.trackListener()方法,这是官方的推荐的写法,用于监听器类型是集合的情况下,如果是set/get之类的那就直接set新的监听器即可。)

然后创建ViewMode:

import androidx.databinding.ObservableField

class UserObservable {

    val number: ObservableField<Int> by lazy {
        ObservableField<Int>()
    }

}

创建Activity,并实现一些基础的显示逻辑:

import android.app.Activity
import android.os.Bundle
import android.view.View
import androidx.databinding.DataBindingUtil
import com.cc.databingdingtest.databinding.MainBinding

class MainActivity: Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: MainBinding = DataBindingUtil.setContentView(this, R.layout.main)
        val userViewMode = UserObservable()
        userViewMode.number.set(0)
        binding.user = userViewMode
        findViewById<View>(android.R.id.content).setOnClickListener {
            userViewMode.number.set(1000)
        }
    }

}

测试一下:

先点击View,然后打断点看看ViewMode里的数据是否会变化。

成功。

然后再看看修改ViewMode数据是否能自动应用到界面上

成功的实现了双向数据绑定  。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值