[翻译] Android Data Binding(6): 双向
2017-03-28 本文已影响113人
luisxu
目前为止, 我已经向你们展示了如何使用Android Data Binding来更新UI及监听UI事件.但我们也会需要另一件事:将用户的输入反馈到程序模块中. Android2.1引入了"双向绑定"来实现这个功能.
双向绑定<a id="orgheadline15"></a>
假设我们有一个表格需要用户填写,里面包括了一个EditText用于接受用户名.单向绑定实现如下:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName" />
通常,你会让用户输入数据然后提交表格. 或者你通过afterTextChanged() 函数来更新你的模块. 除了这样, 你还可以使用双向绑定操作符 @={} 自动将用户改变更新到你的view model中.
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={user.firstName}"/>
由于当用户输入时, model就会自动更新, 我再也不用从EditText中捕获用户名了.同样ID也不再需要了.
双向绑定并不适用于所有属性, 只支持那些会发出"改变通知"的属性. 幸运的是这已经包含了大多数用于输入相关的属性. 由于Android Data Binding要最低兼容到API 7,所以没有新的framework层修改. 否则双向绑定可以支持所有属性.
View属性<a id="orgheadline16"></a>
可以在表达式中访问View的属性, 就像访问数据的属性一样:
<CheckBox
android:id="@+id/showName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{user.firstName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{showName.checked ? View.VISIBLE : View.GONE}"
/>
在上面的配置中, 只有当CheckBox被选中时, 展示用户名的TextView才可见. 这适用于双向绑定及所有可以使用data binding表达式的属性.
<CheckBox
android:id="@+id/showName"
android:focusableInTouchMode="@{model.allowFocusInTouchMode}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{user.firstName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusableInTouchMode="@{showName.focusableInTouchMode}"
/>
上面的例子展示了如何使用表达式链. 在Data Binding框架内部, 当看到"showName.focusableInTouchMode"时,会检查到它绑定到了"model.allowFocusInTouchMode", 并做简单的替换.
View引用<a id="orgheadline17"></a>
另一个很酷的事情是, 你可以在lambda表达式中通过View的ID引用他们.
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/firstName"
android:text="@={user.firstName}" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onCheckedChanged="@{()->handler.checked(firstName)}" />