DataBinding(二)變量及表達式

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是特殊字符,需要使用字符實體進行聲明,例如&lt;表示<,&gt;表示>:

<data>
    <import type="java.util.List"/>
    <variable name="userList" type="List&lt;User&gt;"/>
</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&lt;String&gt;"/>
    <variable name="sparse" type="SparseArray&lt;String&gt;"/>
    <variable name="map" type="Map&lt;String, String&gt;"/>
    <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}"

特殊情況如下:
special expression reference


字符串格式化的方式:

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()方法,第一行會編譯失敗。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章