DataBinding系列:DataBinding的基本用法
轉載自:https://www.jianshu.com/p/70316eb4e0f8
1.在xml中引入一些基礎變數Variables
data 標籤中可以有任意數量的 variable 標籤。這些變數可以使Java中的任意資料型別,每個 variable 標籤描述了會在 binding 表示式中使用的屬性。
<layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="str" type="String"/> <variable name="age" type="int" /> </data> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{str}"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{String.valueOf(age)}"/> </LinearLayout> </layout>
Data Binding和Java一樣,java.lang包裡的類,我們是可以不用匯入包的,也就是說,java基礎型別都是不用導包的。注意:android:text設定int型別的值一定要轉化為String型別,否則系統會認為是資原始檔id,就會出錯*
2.引入一些高階變數Variables
在上面,我們學會了如何在xml中定義變數,以及在控制元件中使用。同樣,我們可以在data中定義像List、Map,陣列等這樣的集合變數,只是它的實現稍微有點不同,下面就一起來看看是如何定義以及使用的。
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <import type="java.util.List" /> <import type="java.util.Map" /> <!--泛型的支援會在編譯時期報紅線,但是是可以直接執行的 但是需要通過轉義字元才行,如:<號用<表示;>號用>表示;--> <variable name="list" type="List<String>" /> <variable name="map" type="Map<String,Object>" /> <variable name="array" type="String[]" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{list[0]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{list.get(1)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@{map[`key0`]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{map.get(`key1`)}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="@{array[0]}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{array[1]}" /> </LinearLayout> </layout>
踩坑:
1、目前遇到as環境中,在xml中Map必須使用泛型,List可以不使用,否則編譯報錯;
2、在xml中使用泛型,不能寫<>,只能使用轉義字元,否則報錯,應如下Map<String,Object>
附:常用的轉義字元
顯示結果 | 描述 | 轉義字元 | 十進位制 |
---|---|---|---|
空格 |  ; |  ; | |
< | 小於號 | <; | <; |
> | 大於號 | >; | >; |
& | 與號 | &; | &; |
" | 引號 | "; | "; |
‘ | 撇號 | &apos; | '; |
× | 乘號 | ×; | ×; |
÷ | 除號 | ÷; | ÷; |
關於獲取list和map的值,我們有2種寫法,[]或者是get(),如果是list或者陣列,需要設定索引下標,如果是map,還需要為它定義key的變數,官方推薦這種集合框架使用[]的寫法。
注意: android:text=""這裡,我用的是雙引號的寫法,官方還有一種單引號的寫法。
單引號
官方說單引號比雙引號更容易使用
android:text='@{map["key0"]}'
雙引號
雙引號當然也是可以的,只是你的key要用``包裹,注意,這個不是單引號,而是Tab鍵上面的那個鍵的那個點。
在Activity中初始化資料,設定這些變數
public class BasicActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityBasicBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_basic);
List<String> list = new ArrayList<>();
list.add("list1");
list.add("list2");
binding.setList(list);
HashMap<String, Object> map = new HashMap<>();
map.put("key0", "map_value0");
map.put("key1", "map_value1");
binding.setMap(map);
String[] arrays = {"字串1", "字串2"};
binding.setArray(arrays);
}
}
3.xml中引用表示式
舉幾個例子,還有很多,大多數Java表示式都是支援的
android:text="@{String.valueOf(age)}"
android:visibility="@{age < 13 ? View.GONE : View.VISIBLE}"
android:text='@{`iname:` +user.name}'
此外還支援null合併操作,它的符號是??,意思是:如果左邊的物件非空則選擇左邊,否則選擇右邊,這和Java中的三目運算子是一樣的,可以算是一個簡略吧。
android:text="@{user.displayName ?? user.lastName}"
//等價於
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
支援的表示式語言
表示式語言與 Java 表示式有很多相似之處。下面是相同之處:
- 數學計算 + - / * %
- 字串連線 +
- 邏輯 && ||
- 二進位制 & | ^
- 一元 + - ! ~
- 位移 >> >>> <<
- 比較 == > < >= <=
- instanceof
- 組 ()
- 字面量 - 字元,字串,數字, null
- 型別轉換
- 函式呼叫
- 欄位存取
- 陣列存取 []
- 三元運算子 ?:
不支援的操作符
一些 Java 中的操作符在表示式語法中不能使用。
- this
- super
- new
- 顯式泛型呼叫 <T>
4.設定別名alias
如果我們import了兩個不同路徑,但名稱相同的類,可以藉助於別名來解決,別名藉助alias欄位來標識,例如:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.zx.databindingdemo.bean.UserBean" />
<!--不同路徑下有2個相同名字的類,那麼給其中一個起一個別名,用alias表示-->
<import type="com.zx.databindingdemo.bean.user.UserBean" alias="UserBean2"/>
<variable
name="user"
type="UserBean" />
<variable
name="user2"
type="UserBean2"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@{`姓名:`+user.name}" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@{`user2:`+user2.content}" />
</LinearLayout>
</layout>
在Activity中
public class BasicActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityBasicBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_basic);
UserBean userBean = new UserBean(URL_USER_PIC, "張三", 24);
binding.setUser(userBean);
com.zx.databindingdemo.bean.user.UserBean userBean2 = new com.zx.databindingdemo.bean.user.UserBean("我是user2");
binding.setUser2(userBean2);
}
5.include中的使用
在使用名稱空間的佈局中,變數可以傳遞到任何 include 佈局中。
<?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}"/>
<include layout="@layout/contact"
app:user="@{user}"/>
</LinearLayout>
</layout>
注意:在name.xml以及contact.xml兩個layout檔案中必需要有user variable
<?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:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{`我的名字`+user.name}"/>
</LinearLayout>
</layout>
Data binding不支援直接包含merge 節點。舉個例子, 以下的程式碼不能正常執行 :
<?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>
<merge>
<include layout="@layout/name"
app:user="@{user}"/>
<include layout="@layout/contact"
app:user="@{user}"/>
</merge>
</layout>
6.事件處理
大家都知道,我們經常需要處理View的點選事件,在xml中android:onClick 可以指定 Activity 中的函式,Data Binding 也允許處理從檢視中傳送的事件。
下面給出幾種實現方式:
- 佈局中引入OnClickListener的變數
- 方法呼叫
佈局中引入OnClickListener的變數
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="clickListener"
type="android.view.View.OnClickListener" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:orientation="vertical">
<Button
android:id="@+id/click_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{clickListener}"
android:text="點我" />
<Button
android:id="@+id/click2_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{clickListener}"
android:text="點我2" />
</LinearLayout>
</layout>
Activity處理點選事件
public class BasicActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityBasicBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_basic);
binding.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.click_btn) {
Toast.makeText(this, "點選了1", Toast.LENGTH_SHORT).show();
} else if (v.getId() == R.id.click2_btn) {
Toast.makeText(this, "點選了2", Toast.LENGTH_SHORT).show();
}
}
}
方法呼叫
相比較於在android:onClick中指定Activity的一個方法,它的優勢在於表示式會在編譯時處理,如果方法不存在或者方法簽名不對,編譯將會報錯。
以下是個例子:
public class OnClickHandler {
public void onClickFriend(View view) {
Toast.makeText(view.getContext(), "onClickFriend", Toast.LENGTH_SHORT).show();
}
}
佈局檔案如下
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="handler"
type="com.zx.databindingdemo.handler.OnClickHandler" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="@{handler::onClickFriend}"/>
<!-- 注意:函式名和監聽器物件必須對應 -->
<!-- 函式呼叫也可以使用 `.` , 如handler.onClickFriend , 不過已棄用 -->
</LinearLayout>
</layout>
別忘了在Activity設定變數
binding.setHandler(new OnClickHandler());