Get into the habit of writing together! This is the third day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the details of the event .
foreword
The default readers of this article have already had a certain understanding of databinding. If you don't know much, you can look at the most complete instructions for using DataBinding. Many people reject databinding, but some people like to use it. Although it is controversial, it does not prevent us from learning and understanding.
This article is about how a custom view binds data in both directions, so that using customization in xml can also achieve the effect of app:customvalue="@={userName}"
app:xx="@{userName}" one-way binding
app:xx="@={userName}" two-way binding
Introduce Databingding
1. The first step is
to introduce the kapt plugin . 2. The second step is to
enable databinding (here is the difference between the new version of gradle and the old version, which version is the specific version, and someone who knows it will tell me in the comment area) The new version of gradle
buildFeatures.dataBinding = true
复制代码
old version of gradle
android{
/.../
dataBinding {
enabled = true;
}
}
复制代码
implementation code
The implementation method provided here is definitely not the optimal solution, or the best, but it is more suitable as a little knowledge to attract others.
1. Let's take a look at the directory of the entire project
2. First, create a new CustomView with a TextView and EditText as a demonstration.
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
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_value"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/purple_200"
android:gravity="center"
android:hint="请选择"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textSize="16dp" />
<EditText
android:id="@+id/et_input"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/teal_700"
android:gravity="center"
android:hint="请输入"
android:textColor="@color/white"
android:textColorHint="@color/white"
android:textSize="16dp" />
</LinearLayout>
复制代码
3. Create a new BindAdapter management class DatabindComponent class to manage related usage, or write the code in it in CustomView by BindMethod
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. Add CustomView in xml, and add two ObservableFields for data monitoring and binding
Summarize
The reason why the GitHub code repository is not posted is because these sample codes are written in the project through Moudle, and some of them are not suitable for release. All the key codes are released, and only some used codes are displayed in the form of pictures. If you happen to have the need to bind custom views in both directions, the above example can completely help you. If you have a better way of writing, you can tell me in the comment area and let me learn