使用单向数据绑定,您可以在属性上设置值并设置一个侦听器来对该属性的变化做出反应。
<CheckBox android:id="@+id/rememberMeCheckBox" android:checked="@{viewmodel.rememberMe}" android:onCheckedChanged="@{viewmodel.rememberMeChanged}" />
双向数据绑定为此过程提供了一种快捷方式。
<CheckBox android:id="@+id/rememberMeCheckBox" android:checked="@={viewmodel.rememberMe}" />
@={}
表示法(重要的是包括“=”号)接收对属性的数据更改并同时侦听用户更新。
为了对后备数据中的更改做出反应,您可以使布局变量成为 Observable
的实现,通常是 BaseObservable
,并使用 @Bindable
注释,如下面的代码片段所示。
Kotlin
class LoginViewModel : BaseObservable { // val data = ... @Bindable fun getRememberMe(): Boolean { return data.rememberMe } fun setRememberMe(value: Boolean) { // Avoids infinite loops. if (data.rememberMe != value) { data.rememberMe = value // React to the change. saveData() // Notify observers of a new value. notifyPropertyChanged(BR.remember_me) } } }
Java
public class LoginViewModel extends BaseObservable { // private Model data = ... @Bindable public Boolean getRememberMe() { return data.rememberMe; } public void setRememberMe(Boolean value) { // Avoids infinite loops. if (data.rememberMe != value) { data.rememberMe = value; // React to the change. saveData(); // Notify observers of a new value. notifyPropertyChanged(BR.remember_me); } } }
由于可绑定属性的 getter 方法称为 getRememberMe()
,因此属性的相应 setter 方法会自动使用名称 setRememberMe()
。
有关使用 BaseObservable
和 @Bindable
的更多信息,请参阅 使用可观察数据对象。
使用自定义属性的双向数据绑定
平台为 最常见的双向属性 和更改侦听器提供了双向数据绑定实现,您可以将其用作应用的一部分。如果您想将双向数据绑定与自定义属性一起使用,则需要使用 @InverseBindingAdapter
和 @InverseBindingMethod
注释。
例如,如果您想在名为 MyView
的自定义视图中的 "time"
属性上启用双向数据绑定,请完成以下步骤。
使用
@BindingAdapter
注释设置初始值并在值更改时更新的方法。Kotlin
@BindingAdapter("time") @JvmStatic fun setTime(view: MyView, newValue: Time) { // Important to break potential infinite loops. if (view.time != newValue) { view.time = newValue } }
Java
@BindingAdapter("time") public static void setTime(MyView view, Time newValue) { // Important to break potential infinite loops. if (view.time != newValue) { view.time = newValue; } }
使用
@InverseBindingAdapter
注释从视图读取值的方法。Kotlin
@InverseBindingAdapter("time") @JvmStatic fun getTime(view: MyView) : Time { return view.getTime() }
Java
@InverseBindingAdapter("time") public static Time getTime(MyView view) { return view.getTime(); }
此时,数据绑定知道在数据更改时该做什么(它调用使用 @BindingAdapter
注释的方法)以及在视图属性更改时该调用什么(它调用 InverseBindingListener
)。但是,它不知道属性何时或如何更改。
为此,您需要在视图上设置一个侦听器。它可以是与自定义视图关联的自定义侦听器,也可以是通用事件,例如焦点丢失或文本更改。将 @BindingAdapter
注释添加到设置属性更改侦听器的方法。
Kotlin
@BindingAdapter("app:timeAttrChanged") @JvmStatic fun setListeners( view: MyView, attrChange: InverseBindingListener ) { // Set a listener for click, focus, touch, etc. }
Java
@BindingAdapter("app:timeAttrChanged") public static void setListeners( MyView view, final InverseBindingListener attrChange) { // Set a listener for click, focus, touch, etc. }
侦听器包含 InverseBindingListener
作为参数。您使用 InverseBindingListener
告诉数据绑定系统属性已更改。然后,系统可以开始调用使用 @InverseBindingAdapter
注释的方法,依此类推。
在实践中,此侦听器包含一些非平凡的逻辑,包括单向数据绑定的侦听器。例如,请参阅文本属性更改的适配器 TextViewBindingAdapter
。
转换器
如果绑定到View
对象的变量需要在显示之前进行格式化、翻译或以某种方式更改,则可以使用Converter
对象。
例如,以一个显示日期的EditText
对象为例。
<EditText
android:id="@+id/birth_date"
android:text="@={Converter.dateToString(viewmodel.birthDate)}"
/>
viewmodel.birthDate
属性包含一个类型为Long
的值,因此需要使用转换器进行格式化。
因为正在使用双向表达式,所以还需要一个反向转换器,以便让库知道如何将用户提供的字符串转换回后备数据类型,在本例中为Long
。此过程是通过在其中一个转换器中添加@InverseMethod
注解,并使此注解引用反向转换器来完成的。以下代码片段显示了此配置的示例。
Kotlin
object Converter { @InverseMethod("stringToDate") @JvmStatic fun dateToString( view: EditText, oldValue: Long, value: Long ): String { // Converts long to String. } @JvmStatic fun stringToDate( view: EditText, oldValue: String, value: String ): Long { // Converts String to long. } }
Java
public class Converter { @InverseMethod("stringToDate") public static String dateToString(EditText view, long oldValue, long value) { // Converts long to String. } public static long stringToDate(EditText view, String oldValue, String value) { // Converts String to long. } }
使用双向数据绑定的无限循环
使用双向数据绑定时,请注意不要引入无限循环。当用户更改属性时,将调用使用@InverseBindingAdapter
注解的方法,并将值分配给后备属性。这反过来又会调用使用@BindingAdapter
注解的方法,这将触发对使用@InverseBindingAdapter
注解的方法的另一次调用,依此类推。
因此,务必通过比较使用@BindingAdapter
注解的方法中的新旧值来中断可能的无限循环。
双向属性
当您使用下表中的属性时,平台为双向数据绑定提供内置支持。有关平台如何提供此支持的详细信息,请参阅相应绑定适配器的实现。
类 | 属性 | 绑定适配器 |
---|---|---|
AdapterView
|
android:selectedItemPosition android:selection |
AdapterViewBindingAdapter
|
CalendarView |
android:date |
CalendarViewBindingAdapter
|
CompoundButton |
android:checked
|
CompoundButtonBindingAdapter
|
DatePicker
|
android:year android:month android:day |
DatePickerBindingAdapter
|
NumberPicker |
android:value
|
NumberPickerBindingAdapter
|
RadioButton
|
android:checkedButton |
RadioGroupBindingAdapter
|
RatingBar
|
android:rating
|
RatingBarBindingAdapter
|
SeekBar
|
android:progress |
SeekBarBindingAdapter
|
TabHost
|
android:currentTab |
TabHostBindingAdapter
|
TextView
|
android:text
|
TextViewBindingAdapter
|
TimePicker
|
android:hour android:minute |
TimePickerBindingAdapter
|
为您推荐
- 注意:当 JavaScript 关闭时,将显示链接文本。
- 使用可观察数据对象
- 布局和绑定表达式
- 将布局视图绑定到架构组件