1. 概述
在DataBinding的佈局文件當中,可以引入各種變量,並在佈局文件中使用變量表達式,達到數據綁定的效果。
引入的變量可以使用完整類名,或者使用標籤導包。與Java一樣,java.lang的包是默認導入的。具體格式及使用方法如下:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@={user.lastName}"/>
</LinearLayout>
</layout>
注意在控件屬性中使用表達式的格式是@{表達式}
,而雙向綁定則是使用@={表達式}
的格式(雙向綁定即控件屬性的改變可以反映到所綁定變量上)。
2. 變量聲明
變量聲明需要使用完整變量名,或者使用標籤進行導包,可以添加alias屬性區分同名不同包的類:
<layout>
<data>
<import type="android.view.View"/>
<import type="com.example.real.estate.View" alias="Vista"/>
</data>
<TextView
android:visibility="@{user.isAdult?View.VISIBLE:View.GONE}"/>
</layout>
對於變量聲明中涉及到泛型的部分,因爲<>在HTML是特殊字符,需要使用字符實體進行聲明,例如<
表示<,>
表示>:
<data>
<import type="java.util.List"/>
<variable name="userList" type="List<User>"/>
</data>
生成的binding類會給每個變量都生成一個getter和setter方法,同時變量會設置一個默認值,即其類型的默認值。另外DataBinding會自動生成一個Context類型的變量context,取值是根佈局的getContext(),我們如果聲明同名變量context可以覆蓋掉這個值。
注意引用變量屬性時,DataBinding必須要有辦法獲取到這個屬性值,因此變量的屬性必須是public或者提供getter或者以字段名爲名的方法來獲取屬性值,否則會報錯。
android:text="@{user.lastName}"
變量
可以在主佈局中傳遞變量到被包含的佈局當中,傳遞方式是通過res-auto命名空間定義變量名屬性,傳入變量名,然後在被包含佈局對該變量進行使用:
主佈局文件:
<?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">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/name"
app:user="@{user}"/>
</LinearLayout>
</layout>
name.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable name="user" type="com.example.User"/>
</data>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:textColor="@color/colorPrimaryDark"
android:layout_height="wrap_content"
android:text="@{user.name}">
</TextView>
</layout>
注意標籤不能包含在標籤當中:
<!-- 錯誤做法 -->
<merge>
<include layout="@layout/name" bind:user="@{user}"/>
</merge>
3. 表達式
DataBinding中表達式可以使用java大部分運算符及關鍵字,還可以調用方法,例如:
android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
不支持的運算符:this、super、new、顯式的泛型調用。
DataBinding新增了一個雙目運算符 ??,如果左邊表達式結果非空,則使用左邊表達式結果,否則使用右邊表達式結果。
android:text="@{user.displayName ?? user.lastName}"
DataBinding表達式中是可以自動避免空指針異常的,比如@{user.name}
,如果user爲空,不會拋出異常,而是返回默認值,如null、0、false。
如果表達式當中需要使用到字符串,可以直接把屬性值的雙引號改爲單引號,或者字符串常量使用單引號’或者反引號`:
android:text='@{map["firstName"]}'
android:text="@{map[`firstName`]}"
android:text="@{map['firstName']}"
集合元素的元素獲取使用[]進行獲取:
<data>
<import type="android.util.SparseArray"/>
<import type="java.util.Map"/>
<import type="java.util.List"/>
<variable name="list" type="List<String>"/>
<variable name="sparse" type="SparseArray<String>"/>
<variable name="map" type="Map<String, String>"/>
<variable name="index" type="int"/>
<variable name="key" type="String"/>
</data>
<TextView
android:text="@{list[index]}"
android:text="@{sparse[index]}"
android:text="@{map[key]}" />
資源引用的方式除了特殊情況外使用正常語法引用即可:
android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"
特殊情況如下:
字符串格式化的方式:
android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"
字符串資源文件聲明:
<string name="nameFormat">nameFormat with %1$s and %2$s</string>
原生Android XML屬性的運行方式是View當中提供自定義屬性,然後View會從XML中獲取屬性值再進行操作。
而當XML屬性中使用了DataBinding表達式時,則運行方式就變爲從View當中去查找屬性對應的setter方法並進行調用,如果找不到就會報錯,例如:
android:layout_marginLeft="@{isError?@dimen/wide:@dimen/narrow}"
android:padding="@{isError?@dimen/wide:@dimen/narrow}"
因爲View當中有setPadding()方法,第二行可以編譯成功,而沒有setMarginLeft()方法,第一行會編譯失敗。