適用於Android開發者的Databinding自定義view雙向綁定

語言: CN / TW / HK

一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第3天,點擊查看活動詳情

前言

本篇默認讀者已經對databinding 有過一定的瞭解,如果不甚瞭解,可以看看東哥的DataBinding最全使用説明,很多人排斥databinding,但也有人喜歡使用。雖然它有爭議,但是不妨礙我們去學習、瞭解。\ 本篇講述的是自定義view如何來雙向綁定數據,來實現在xml中使用自定義也能達到 app:customvalue="@={userName}"的效果

app:xx="@{userName}" 單向綁定\ app:xx="@={userName}" 雙向綁定

引入Databingding

1、第一步 \ 引入kapt插件 image.png 2、第二步 \ 開啟databinding(這裏有 gradle新版跟舊版的區別,具體是哪個版本,有知道的評論區告訴我) 新版本的gradle buildFeatures.dataBinding = true image.png 舊版本的gradle android{ /.../ dataBinding { enabled = true; } }

實現代碼

這裏提供的實現方法肯定不是最優解,或者説是最好的,但是作為拋磚引玉的小知識,是比較適合的

1、先給大家看一下整個工程的目錄

image.png

2、首先,新建一個CustomView、裏面有一個TextView、EditText來作為演示。 ``` class CustomView(mContext: Context, attributeSet: AttributeSet?) : LinearLayout(mContext, attributeSet) { private var onChangeListener: InverseBindingListener? = null private var onInputChangeListener: InverseBindingListener? = null private var itemInput: EditText? = null private var itemText: TextView? = null var etInput = "" set(value) { val oldValue = field if (value == oldValue) { return; } field = value onInputChangeListener?.onChange() }

var tvValue = ""
    set(value) {
        val oldValue = field
        if (value == oldValue) {
            return;
        }
        field = value
        onChangeListener?.onChange()
    }

init {
    initView(mContext, attributeSet)
}


private fun initView(mContext: Context, attributeSet: AttributeSet?) {
    val view = inflate(mContext, R.layout.widget_custom_view, this)
    itemInput = view.findViewById(R.id.et_input)
    itemText = view.findViewById(R.id.tv_value)
    itemText?.setOnClickListener {
        tvValue = System.currentTimeMillis().toString()
        itemText?.text = tvValue
    }
    itemInput?.doOnTextChanged { text, start, before, count ->
        etInput = text.toString()
    }
}

internal fun setOnInputChangeListener(listener: InverseBindingListener) {
    if (onInputChangeListener == null) {
        this.onInputChangeListener = listener
    }
}

internal fun setOnValueChangeListener(listener: InverseBindingListener) {
    if (onChangeListener == null) {
        this.onChangeListener = listener
    }
}

} widget_custom_view.xml

3、新建一個BindAdapter管理類 DatabindComponent類來管理相關使用,也可以將其中的代碼 通過BindMethod的方式寫在CustomView中 object DataBindComponent {

@BindingAdapter("itemInput")
@JvmStatic
fun CustomView.setItemInputParams(value: String) {
    etInput = value
}

@InverseBindingAdapter(attribute = "itemInput", event = "itemInputAttrChanged")
@JvmStatic
fun getItemInputParams(view: CustomView): String {
    return view.etInput
}

@BindingAdapter(value = ["itemInputAttrChanged"], requireAll = false)
@JvmStatic
fun CustomView.itemPutChange(textAttrChanged: InverseBindingListener) {
    setOnInputChangeListener(textAttrChanged)
}

@BindingAdapter("itemValue")
@JvmStatic
fun CustomView.setItemValueParams(value: String) {
    tvValue = value
}

@InverseBindingAdapter(attribute = "itemValue", event = "itemValueAttrChanged")
@JvmStatic
fun getItemValueParams(view: CustomView): String {
    return view.tvValue
}

@BindingAdapter(value = ["itemValueAttrChanged"], requireAll = false)
@JvmStatic
fun CustomView.itemValueChange(textAttrChanged: InverseBindingListener) {
    setOnValueChangeListener(textAttrChanged)
}

} ``` 4、在xml中添加CustomView,並添加兩個ObservableField 來進行數據的監聽綁定

image.png

image.png

總結

沒有貼GitHub代碼倉庫的原因是因為這些示例代碼,是通過Moudle的方式寫在project中,其中一些Moudle不適合放開。關鍵代碼全都將其放了出來,只有一些使用的代碼,通過圖片形式展示。如果你剛好有將自定義view雙向綁定的需求,以上示例,完全可以幫助到你,如果你有更好的寫法,可以在評論區告訴我,讓我學習