Data Binding 詳解(二)-布局和綁定表達式

http://newdocx.appcan.cn/data-docking-interaction/MVVM

本章將講解在 Data Binding 中的布局及布局中如何使用表達式柬甥。

支持的表達式

在布局中支持很多表達式和關鍵字:

數學運算: + - / * %

字符串連接: +

邏輯運算符: && ||

二進制運算符: & | ^

一元運算符: + - ! ~

轉變運算符(位移): >> >>> <<

比較運算符: == > < >= <=

instanceof: 類型判斷

Grouping ()

Literals - character,?String, numeric, null

Cast

Method calls

Field access

Array access []

三元運算符: ?:


看上去支持大部分表達式称开,但是在寫起來往往會遇到問題徘郭,會編譯都不過,這是因為在布局中有很多符號是不能直接使用的婉刀,需要轉義一下巢钓,比如小于號<要寫成&lt;唉窃,轉義知識請自行學習窟蓝。例如:

<!--android:visibility="@{age < 10 ? View.GONE : View.VISIBLE}"此句編譯不過-->android:visibility="@{age &lt; 10 ? View.GONE : View.VISIBLE}"

注意:如果這段代碼你直接拷貝到你項目中,可能依然編譯不過旭等,這是因為你沒有導入 View 包酌呆,在布局中寫表達式的時候特別要注意這一點,因為?java?文件寫慣了搔耕,導包都是自動的隙袁,而在布局中則需要手動導入,需要在布局中的 data 標簽中這樣寫:<import type="android.view.View" />弃榨,import?后面也會專門講解菩收。

空合并運算符

上面的運算符和表達式在 java 代碼中應該都用過,但空合并運算符可能比較陌生鲸睛,空合并運算符是通過兩個問號來表達???娜饵,如果左操作數不為 null,則選擇左操作數官辈,如果為 null箱舞,則選擇右操作數。

android:text="@{user.remark ?? user.name}"

這在功能上等同于:

android:text="@{user.remark != null ? user.remark : user.name}"

表達式中使用集合

為了方便使用拳亿,可以使用[]運算符訪問常用集合晴股,如數組、List肺魁、和Map电湘。下面在 UserInfo 中增加了幾個集合數據:


布局中的使用:


代碼中設置索引:


Map 的使用也可以直接引用 key 值,寫成這樣:

<TextView...android:text="@{@string/task(user.task.monday), default=今天任務}".../>

表達式中使用字符串

在布局中避免不了直接使用字符串,你可以使用單引號來包圍屬性值寂呛,這允許你在表達式中使用雙引號怎诫,如下面的例子所示:

android:text='@{@string/task(user.task["monday"]), default=今天任務}'

還可以使用雙引號來包圍屬性值, 這個時候字符串文本就需要被反引號包圍(反引號就是鍵盤的第二排第一個這個鍵值):

android:text="@{@string/task(user.task[`monday`]), default=今天任務}"

表達式中引用資源

使用正常的表達式來訪問 Resources 也是可行的:


這里引用了 dimen 和 string贷痪,string 還可以帶格式化參數幻妓,當然也可以引用復數,但是一般情況下我們用不到劫拢,因為中文沒有這個需求涌哲。比如:

android:text="@{@plurals/banana(bananaCount)}"

除了這些,還支持其他的資源引用尚镰,但有些資源的引用需要明確指明類型,如下表所示:


事件綁定

Data Binding 允許你編寫表達式來處理 View 分派的事件哪廓。事件屬性名字取決于監(jiān)聽器方法名字狗唉。例如 View.OnClickListener 有 onClick() 方法,View.OnLongClickListener 有 onLongClick() 的方法涡真,因此事件的屬性是?android:onLongClick分俯,android:onClick。

對于 click 事件哆料,為了避免多種 click 事件的沖突缸剪,Google也定義了一些專門的事件處理,比如:


除了它們东亦,Google 還定義了其他一些常用的綁定事件的屬性杏节,這些可以閱讀 Data Binding 源碼(android.databinding.adapters 包下)或者?Google 官方 Data Binding 的 API

事件綁定有兩種使用方式:引用方法綁定監(jiān)聽器典阵。接下來將具體介紹這兩種方式的使用奋渔。

引用方法

可以引用綁定對象中已經定義好的特定規(guī)則的 click 方法:


布局中的使用:

注意:被綁定的方法有一個 View 參數,這個參數是必須的壮啊,因為 Data Binding 在引用方法時嫉鲸,需要方法的參數和返回值必須與事件監(jiān)聽器的參數和返回值相匹配,如果參數或者返回值不匹配則會在編譯時報錯歹啼。

當表達式計算為引用方法的方式時玄渗,Data Binding 在監(jiān)聽器中包裝引用方法和所有者對象,并在目標 View 上設置該監(jiān)聽器狸眼,但是監(jiān)聽器對象是在數據綁定的時候創(chuàng)建的藤树,如果綁定的對象為空,這個監(jiān)聽器則不會創(chuàng)建份企。引用方法方式的優(yōu)點是找不到符合規(guī)定的方法則編譯報錯也榄。

綁定監(jiān)聽器

綁定監(jiān)聽器是在布局中寫一個 lambda 表達式,表達式是在事件發(fā)生時被求值。它類似于引用方法甜紫,但允許你運行任意的數據綁定表達式降宅。這個特性是在 Android Gradle Plugin for Gradle version 2.0 或更高版本中才支持。以下示例為一個頁面跳轉的 click 事件綁定:


聲明了一個 startList() 方法囚霸,接著把按鈕點擊事件綁定到 startList() 方法上:


引用方法的方式中腰根,方法的參數和返回值必須與事件監(jiān)聽器的參數和返回值相匹配。 在綁定監(jiān)聽器的方式中拓型,則只要返回值與監(jiān)聽器的預期返回值匹配即可额嘿。 例如:


一個長按事件的處理需要返回一個 Boolean 類型的值:


綁定監(jiān)聽器在編譯時會自動創(chuàng)建必要的監(jiān)聽器并為它注冊事件(監(jiān)聽器是一開始就創(chuàng)建好了,等到觸發(fā)時才會判斷被綁定的對象是否為空劣挫,為空則不執(zhí)行任何操作)册养。 當 View 觸發(fā)事件時,Data Binding 才會計算給定的表達式压固,在計算這些表達式時可以獲得 Data Binding 的 null 安全和線程安全性球拦。

有些時候 Click 方法可能需要帶一些必要的參數,比如:



在上面例子中帐我,showSign 方法需要一個 View 和 UserInfo 對象坎炼,在布局中這樣使用?@{(view)->activity.showSign(view, user)},view 是 lambada 表達式中獲取的拦键,user 是上面聲明需綁定的變量谣光。如果綁定方法是多個參數,或者監(jiān)聽器事件是帶返回值的都是以此類推芬为,保證參數和返回值匹配即可萄金。

如果需要使用帶有謂詞的表達式(例如,三元表達式) 碳柱,可以使用監(jiān)聽器相匹配的返回值類型作為表達式捡絮,比如 onCLick 屬性使用 void,onLongClick 屬性使用 Boolean莲镣。

android:onClick="@{(view)->view.isEnabled()?activity.showSign(view, user):void}"

android:onLongClick="@{(v)->v.isEnabled()?activity.showSign(user):false}"


注意:監(jiān)聽器表達式非常強大福稳,可以使您的代碼簡化,容易閱讀瑞侮。另一方面的圆,如果包含復雜表達式的監(jiān)聽器也會使你的布局難以理解和維護。布局中表達式應該盡量的簡單半火,你應該在監(jiān)聽器表達式調用的回調方法中實現(xiàn)相對復雜的業(yè)務邏輯越妈。

布局中的一些關鍵標簽

Data Binding 庫提供了?import,?variable?以及?include?標簽,import?使得可以在布局文件中引用類钮糖。variable?允許你聲明可在綁定表達式中使用的變量梅掠。include?可以讓你重用布局酌住。

Import

import?可以讓你在布局中使用類,比如導入 View 類阎抒,導入 View 類允許你在綁定表達式中引用它的常量 VISIBLE 和 GONE酪我。


當存在類名沖突時,還可以將其中一個類重命名為別名且叁。 下面的示例將?com.example.databindingdemo.bean 包中的 View 類重命名為 Vista都哭,這樣可以使用 Vista 引用 com.example.databindingdemo.bean.View 類,使用 View 來引用系統(tǒng)中的 android.View.View逞带。


導入的類型可以用作變量和表達式中的類型引用欺矫。下面的示例顯示了用作變量類型的 UserInfo:

<importtype="com.example.databindingdemo.bean.UserInfo"/><variablename="user"type="UserInfo"/>

它等同于:

<variablename="user"type="com.example.databindingdemo.bean.UserInfo"/>

也可以導入類來做類型轉換,或者導入工具類來使用它的靜態(tài)方法:


但不是所有類都需要自己導包展氓,基本數據類型穆趴,String,以及 Data Binding 自己本身提供的 Observable 相關的類編譯器會自動導入遇汞。

Variable

可以在?data?標簽內部使用多個?variable毡代。 每個 variable 描述一個變量,該變量可以在布局文件中的綁定表達式中使用勺疼。下面的示例聲明了 UserInfo、Drawable 和 String 變量:

<data>

<variablename="user"type="com.example.User"/><variablename="image"type="android.graphics.drawable.Drawable"/><variablename="note"type="String"/>

</data>

在自動生成的綁定類中具有每個變量的 setter 和 getter 方法捏鱼,這些變量在調用 setter 方法賦值之前都有默認值执庐,對象為 null,int 為 0导梆,boolean 為 false 等等轨淌。同時也會生成一個名為 context 的特殊變量,以便根據需要在綁定表達式中使用看尼。context 的值是根 View 的 getContext()方法中的 Context 對象递鹉。以下為直接通過 context 變量獲取程序包名:

<TextView...android:text="@{context.packageName}".../>

但 context 變量可以被具有該名稱的顯式變量聲明所覆蓋,比如聲明了一個 String 類型的 context 變量:

<variablename="context"type="String"/>

這個時候就不能直接使用?@{context.packageName}?了藏斩,因為 context 已經被覆蓋為 String 類型躏结。

注意:當設備針對橫豎屏有不同的布局文件時,這些布局文件之間不能有沖突的變量定義狰域,必須保證不同配置的布局文件中的變量是一致的媳拴。

Include

include?標簽和普通布局中使用的?include?是一樣的功能,都是導入一個已經存在的布局文件兆览,來實現(xiàn)布局的重用屈溉。只不過在 Data Binding 中它多了綁定數據的功能。下面展示了來自?layout_avatar.xml?布局文件:


這個布局很簡單抬探,里面只有一個 ImageView子巾,里面聲明了一個表達式?app:image="@{resId}"(這是一個自定義的適配器,自定義適配器后面會講到,這里不深究)线梗,它需要一個?resId?的變量椰于,接下來展示在?activity_user.xml?布局中的使用:

<data>

<import type="com.example.databindingdemo.bean.UserInfo"/><variable name="user"type="UserInfo"/>...

</data>..

.<include layout="@layout/layout_avatar"bind:resId="@{user.avatarId}"/>...

在布局中?include?了?layout_avatar.xml?文件,并聲明了一個屬性且綁定了表達式bind:resId="@{user.avatarId}"缠导,這個屬性就是?layout_avatar.xml?文件中的?resId?變量廉羔,它的規(guī)則就是:被?include?的布局里面的變量名就是這里綁定的屬性名。遵循這個規(guī)則僻造,就可以為?layout_avatar.xml?布局中的?resId?變量賦值憋他。

注意:Data Binding 不支持在 merge 標簽中直接 include 布局。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末髓削,一起剝皮案震驚了整個濱河市竹挡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌立膛,老刑警劉巖揪罕,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宝泵,居然都是意外死亡好啰,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門儿奶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來框往,“玉大人,你說我怎么就攤上這事闯捎∫祝” “怎么了?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵瓤鼻,是天一觀的道長秉版。 經常有香客問我,道長茬祷,這世上最難降的妖魔是什么清焕? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮祭犯,結果婚禮上耐朴,老公的妹妹穿的比我還像新娘。我一直安慰自己盹憎,他們只是感情好筛峭,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著陪每,像睡著了一般影晓。 火紅的嫁衣襯著肌膚如雪镰吵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天挂签,我揣著相機與錄音疤祭,去河邊找鬼。 笑死饵婆,一個胖子當著我的面吹牛勺馆,可吹牛的內容都是我干的。 我是一名探鬼主播侨核,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼草穆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搓译?” 一聲冷哼從身側響起悲柱,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎些己,沒想到半個月后豌鸡,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡段标,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年涯冠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逼庞。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡功偿,死狀恐怖,靈堂內的尸體忽然破棺而出往堡,到底是詐尸還是另有隱情,我是刑警寧澤共耍,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布虑灰,位于F島的核電站,受9級特大地震影響痹兜,放射性物質發(fā)生泄漏穆咐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一字旭、第九天 我趴在偏房一處隱蔽的房頂上張望对湃。 院中可真熱鬧,春花似錦遗淳、人聲如沸拍柒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拆讯。三九已至脂男,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間种呐,已是汗流浹背宰翅。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爽室,地道東北人汁讼。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像阔墩,于是被迫代替她去往敵國和親嘿架。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內容