適用於Android開發者的Databinding自定義view雙向繫結
一起養成寫作習慣!這是我參與「掘金日新計劃 · 4 月更文挑戰」的第3天,點選檢視活動詳情。
前言
本篇預設讀者已經對databinding 有過一定的瞭解,如果不甚瞭解,可以看看東哥的DataBinding最全使用說明,很多人排斥databinding,但也有人喜歡使用。雖然它有爭議,但是不妨礙我們去學習、瞭解。\ 本篇講述的是自定義view如何來雙向繫結資料,來實現在xml中使用自定義也能達到 app:customvalue="@={userName}"的效果
app:xx="@{userName}" 單向繫結\ app:xx="@={userName}" 雙向繫結
引入Databingding
1、第一步 \
引入kapt外掛
2、第二步 \
開啟databinding(這裡有 gradle新版跟舊版的區別,具體是哪個版本,有知道的評論區告訴我)
新版本的gradle
buildFeatures.dataBinding = true
舊版本的gradle
android{
/.../
dataBinding {
enabled = true;
}
}
實現程式碼
這裡提供的實現方法肯定不是最優解,或者說是最好的,但是作為拋磚引玉的小知識,是比較適合的
1、先給大家看一下整個工程的目錄
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
總結
沒有貼GitHub程式碼倉庫的原因是因為這些示例程式碼,是通過Moudle的方式寫在project中,其中一些Moudle不適合放開。關鍵程式碼全都將其放了出來,只有一些使用的程式碼,通過圖片形式展示。如果你剛好有將自定義view雙向繫結的需求,以上示例,完全可以幫助到你,如果你有更好的寫法,可以在評論區告訴我,讓我學習