1、概述
通過半年的使用發現,databinding 有三種自定義屬性的方式。分別是:
- 1、xml 引入自定義屬性標籤。代碼通過 @BindingAdapter 註解完成綁定
- 2、直接在代碼裏使用:@BindingMethods 註解引入自定義屬性,再用@BindingAdapter 註解完成綁定
- 3、自定義控件屬性時,提供set的方法 可以自動完成支持 databinding 屬性。 屬性名字=控件的自定義屬性名字 (所以有時候,發現沒有特定使用@BindingAdapter 也支持了 databinding)
2、實例
2.1、xml 引入自定義屬性標籤。代碼通過 @BindingAdapter 註解完成綁定
xml 文件:
<declare-styleable name="AdapterView">
<!--只能設置在 checkbox 中-->
<attr name="setCheckValue" format="boolean"/>
</declare-styleable>
代碼文件:
public class ViewAdapter {
@BindingAdapter({"setCheckValue"})
public static void setCheckValue(final CheckBox checkBox, final ObservableField<Boolean> tags){
tags.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
checkBox.setChecked(tags.get());
}
});
}
}
注意: xml 裏定義attr name的時候, 如果沒有加上 format 標籤, 在xml佈局中使用的時候沒法跳轉到 自定義的這個屬性。加了纔可以跳轉
這裏代碼使用的java的代碼, java代碼對應是static 靜態函數。 對應kotlin代碼 要用靜態的方式 有幾種方式:
2.1.1、比如最外層用kotlin的單例寫, 方法前加 @JvmStatic 註解:
比如 :
object LinearLayoutViewAdapter {
@JvmStatic
@Suppress("UNCHECKED_CAST")
@BindingAdapter(value = ["itemBinding", "items"], requireAll = false)
fun <T> setAdapter(linearLayout: LinearLayout,
itemBinding: ItemBinding<T>?,
items: List<T>?) {
requireNotNull(itemBinding) { "itemBinding == null" }
val oldAdapter: BindingLinearLayoutAdapter<T>? = linearLayout.getAdapter() as? BindingLinearLayoutAdapter<T>
val adapter = oldAdapter ?: BindingLinearLayoutAdapter()
adapter.itemBinding = itemBinding
adapter.setItems(items)
if (adapter != oldAdapter) {
linearLayout.setAdapter(adapter)
}
}
}
2.1.2、用 kotin的擴展函數來寫:
比如 下文的代碼
@BindingAdapter(value = ["labelCheckChecked"], requireAll = false)
fun LabelCheckBoxView.setEnable(labelCheckChecked: Boolean) {
this.getCheckBox().isChecked = labelCheckChecked
}
2.1.3、kotlin 還有一種寫靜態的方法,是以函數式編程的方式,不套類,直接寫一個函數。
比如:谷歌官網的demo寫法
@BindingAdapter("android:paddingLeft")
fun setPaddingLeft(view: View, padding: Int) {
view.setPadding(padding,
view.getPaddingTop(),
view.getPaddingRight(),
view.getPaddingBottom())
}
2.2、@BindingMethods + @BindingAdapter 的方式
不需要在xml中寫屬性,直接用代碼。使用的時候 也會提示補全
@RestrictTo(RestrictTo.Scope.LIBRARY)
@BindingMethods(BindingMethod(type = LabelCheckBoxView::class, attribute = "onCheckedChangedCommand", method = "setCheckedChanged"),
BindingMethod(type = LabelCheckBoxView::class, attribute = "labelCheckChecked", method = "setEnable"))
class ViewAdapter
/**
* 綁定改變事件
* Desc:
* <p>
* Author: LiWei
* Date: 2019-12-27
* @receiver LabelCheckBoxView
* @param bindingCommand BindingCommand<Boolean>
*/
@BindingAdapter(value = ["onCheckedChangedCommand"], requireAll = false)
fun LabelCheckBoxView.setCheckedChanged(bindingCommand: BindingCommand<Boolean>) {
this.getCheckBox().setOnCheckedChangeListener { compoundButton, b -> bindingCommand.execute(b) }
}
@BindingAdapter(value = ["labelCheckChecked"], requireAll = false)
fun LabelCheckBoxView.setEnable(labelCheckChecked: Boolean) {
this.getCheckBox().isChecked = labelCheckChecked
}
2.3、自定義控件屬性時,提供set的方法 直接支持databinding
自定義屬性:
<declare-styleable name="LabelCheckBoxView">
<attr name="labCheckTip" format="string" />
<attr name="labCheckSelect" format="boolean" />
</declare-styleable>
class LabelCheckBoxView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
/**
* 左邊Tv
*/
private var tipStr: String? = ""
init {
orientation = HORIZONTAL
View.inflate(context, R.layout.widget_label_checkbox, this)
if (attrs != null) {
val a = getContext().obtainStyledAttributes(attrs, R.styleable.LabelCheckBoxView)
if (a.hasValue(R.styleable.LabelCheckBoxView_labCheckTip)) {
tipStr = a.getString(R.styleable.LabelCheckBoxView_labCheckTip)
}
//設置延展模式, 左右對齊方式
if (a.hasValue(R.styleable.LabelCheckBoxView_labCheckSelect)) {
switchLabel.isSelected = a.getBoolean(R.styleable.LabelCheckBoxView_labCheckSelect, false)
}
a.recycle()
}
tvLabelTip.text = tipStr
}
...
...
/**
* 這個需要留着,用自定義屬性支持 dataBinding
* Desc:
* <p>
* Author: xx
* Date: 2019-12-27
* @param str String
*/
fun setLabCheckTip(str: String) {
tvLabelTip.text = str
}
/**
* 這個需要留着,用自定義屬性支持 dataBinding
* Desc:
* <p>
* Author: xx
* Date: 2019-12-27
* @param select Boolean
*/
fun setLabCheckSelect(select: Boolean) {
switchLabel.isSelected = select
}
}
3、參考
【1】、官網https://developer.android.com/topic/libraries/data-binding/binding-adapters#kotlin
【2】、androidx.databinding.adapters 源碼