BaseObservable DataBinding Progression 3 BindingAdapter and BindingConversion DataBinding progression 4 Two-way data binding
4. BindingAdapter
The BindingAdapter is used as a framework for setting a value. There are generally three ways to set a value.
- Automatic selection method
- Use @bindingMethods (specify custom method names)
- @bindingAdapter (provides custom logic)
4.1 Automatic selection method
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}" />
Copy the code
For example, android:text=”@{user.name}”. The library automatically looks for setText methods whose parameters are of type user.name. For example, if user.name is returned as String, the library will automatically look for setText(String) methods to call. So that’s how you automatically look it up.
4.2 @ BindingMethods usage
@bindingMethods is an annotation provided by the DataBinding library to map a property in a View to its corresponding setter method name, For example, android:textColorHint is the same method as setHintTextColor. In this case, the name of the property is inconsistent with the name of the corresponding setter method. This requires binding the property to the corresponding setter method using the @bindingMethods annotation so that DataBinding can find the corresponding setter method based on the property value. Example from TextView source:
@BindingMethods({
@BindingMethod(type = TextView.class, attribute = "android:autoLink", method = "setAutoLinkMask").@BindingMethod(type = TextView.class, attribute = "android:drawablePadding", method = "setCompoundDrawablePadding").@BindingMethod(type = TextView.class, attribute = "android:editorExtras", method = "setInputExtras").@BindingMethod(type = TextView.class, attribute = "android:inputType", method = "setRawInputType").@BindingMethod(type = TextView.class, attribute = "android:scrollHorizontally", method = "setHorizontallyScrolling").@BindingMethod(type = TextView.class, attribute = "android:textAllCaps", method = "setAllCaps").@BindingMethod(type = TextView.class, attribute = "android:textColorHighlight", method = "setHighlightColor").@BindingMethod(type = TextView.class, attribute = "android:textColorHint", method = "setHintTextColor").@BindingMethod(type = TextView.class, attribute = "android:textColorLink", method = "setLinkTextColor").@BindingMethod(type = TextView.class, attribute = "android:onEditorAction", method = "setOnEditorActionListener"),})public class TextViewBindingAdapter {
/ /...
}
Copy the code
CustomTextView: Android :custom_text calls the showCustomToast method
@BindingMethods(value = [
BindingMethod(type = androidx.appcompat.widget.AppCompatTextView::class,attribute = "android:custom_text",method = "showCustomToast")
])
class CustomTextView :AppCompatTextView{
constructor(context: Context):this(context,null.0)
constructor(context: Context, attrs: AttributeSet?) :this(context,attrs,0)
constructor(context: Context, attrs: AttributeSet? , defStyleAttr:Int=0) :super(context,attrs,0)
fun showCustomToast(text:String){
Toast.makeText(context,text,Toast.LENGTH_SHORT).show()
}
}
Copy the code
The XML layout code is as follows:
<? xml version="1.0" encoding="utf-8"? > <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.example.jepcaktestapp.databinding.Teacher"/>
<variable
name="teacher"
type="Teacher" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.jepcaktestapp.databinding.CustomTextView
android:id="@+id/customTextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="CustomTextView"
android:custom_text="@{teacher.name}"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code
Android :custom_text=”@{teach.name}” We can see that the Android :custom_text layout is called in this form. The showCustomToast method in the CustomTextView class is called. That’s what the BindingMethod does. Other complete code
class DataBindingTestActivity :AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityDatabindingtestBinding>(this,R.layout.activity_databindingtest)
binding.teacher = Teacher().apply{
name = "ccm"
age = 1}}}class Teacher {
var name =""
var age = 0
}
Copy the code
4.3 Usage of BindingAdapter
BindingAdapter generally has two scenarios. One is to perform some custom logical processing on the existing attributes. One is completely custom properties, custom logic.
4.3.1 Custom logic for Existing Attributes
The BindingAdapter can be used when some attributes require custom logic. Examples are as follows:
object TextViewAdapter {
@JvmStatic
@BindingAdapter("android:text")
fun setText(textView: TextView, text: CharSequence) {
val str = text.toString().toLowerCase()
textView.text = str+"=ccmend="
}
}
<TextView
android:id="@+id/tv_teacher_name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="@{teacher.name}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_teacher_name2"
app:layout_constraintTop_toBottomOf="@+id/tv_teacher_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="CTest"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Copy the code
- @bindingAdapter (” Android :text”) We redefined the logic of Android :text. When using DataBinding’s setText, val STR = text.tostring ().tolowercase () changes the content toLowerCase, Textview.text = STR +”= CCMEND =” and add the string “= CCMEND =” to the end.
- The first TextView uses android:text=”@{teacher.name}”, which is a DataBinding form, so when we pass in teacher.name as CTest, we will finally input CTest = ccMEND =
- The two TextViews do not use DataBinding, so CTest is output.
This is the first use of the @BindingAdapter, which allows you to customize the logic for certain attributes
4.3.2 Customizing Attributes
We can customize the attributes to use the following code:
object ImageViewAdapter {
@JvmStatic
@BindingAdapter("imageurl")
fun loadImage(imageView: ImageView, imageUrl: String) {
Glide.with(imageView.context).load(imageUrl).into(imageView)
}
}
Copy the code
XML layout
<? xml version="1.0" encoding="utf-8"? > <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.example.jetpackdatabindingtestapp.ui.model.Driver"/>
<variable
name="driver"
type="Driver" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_width="wrap_content"
app:imageurl="@{driver.url}"
android:layout_height="wrap_content"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Copy the code
The activity code:
class BindingAdapterActivity :AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivityBindingadapterTestBinding>(this,R.layout.activity_bindingadapter_test)
binding.driver = Driver().apply{
name = "ccm"
age = 1
url = "https://www.baidu.com/img/bd_logo1.png"}}}Copy the code
You can also use adapters that accept multiple properties
@JvmStatic
@BindingAdapter("imageurl"."errorD"."placeholderD")
fun loadImage(imageView: ImageView, imageUrl: String,errorDrawable:Drawable,placeholderDrawble:Drawable){ Glide.with(imageView.context).load(imageUrl).apply(RequestOptions().error(errorDrawable).placeholder(placeholderDrawble) ).into(imageView) }// Use of XML
<ImageView
android:id="@+id/iv_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/customTextView"
android:layout_width="wrap_content"
app:imageurl="@{driver.url}"
app:errorD="@{@drawable/ic_launcher_background}"
app:placeholderD="@{@drawable/ic_launcher_background}"
android:layout_height="wrap_content"/>
Copy the code
If you want to make multiple properties optional, you simply add a requireAll variable.
@JvmStatic
@BindingAdapter(value=["imageurl"."errorD"."placeholderD"],requireAll = false)
fun loadImage(imageView: ImageView, imageUrl: String,errorDrawable:Drawable,placeholderDrawble:Drawable){ Glide.with(imageView.context).load(imageUrl).apply(RequestOptions().error(errorDrawable).placeholder(placeholderDrawble) ).into(imageView) }// In this XML layout, use one parameter, but both parameters are acceptable
<ImageView
android:id="@+id/iv_image"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/customTextView"
android:layout_width="wrap_content"
app:imageurl="@{driver.url}"
app:errorD="@{@drawable/ic_launcher_background}"
android:layout_height="wrap_content"/>
Copy the code
RequireAll = false. Indicates that the custom properties are selected so that when the layout is used, you do not need to write all the properties.
Five: BindingConversion
Data, or types, can be converted using BindingConversion. Examples of data conversion:
@BindingConversion
@JvmStatic
fun setText(text: String):String{
return "$text=Add=ConversionEnd="
}
Copy the code
The XML file
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text='@{"CTest"}'
android:textAllCaps="false"/>
Copy the code
Add= Add=ConversionEnd= string after using the suffix to the string. The final output will be “CTest=Add=ConversionEnd=” type conversion example:
@BindingConversion
@JvmStatic
fun conversionToDrawable(text: String):Drawable{
return when(text){
"Red"->ColorDrawable(Color.RED)
else->ColorDrawable(Color.WHITE)
}
}
Copy the code
XML key code:
<TextView
android:id="@+id/tv_teacher_name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text="CTest"
android:background="@ {` red `}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Copy the code
Android :background=”@{red}” {BindingConversion = String = Drawable; The TextView background is red when you run it. Indicates that the conversion is successful. Note: If BindingConversion and BindingAdapter are used. Both take effect, but the BindingConversion takes precedence over the BindingAdapter.