繫結轉接器負責對
設定值。其中一個例子是設定屬性值,例如呼叫
setText()
方法,增加圍繞地圖邊緣的邊框間距。其他
例如設定事件監聽器,例如呼叫
setOnClickListener()
敬上
方法。
資料繫結程式庫可讓您指定呼叫方法來設定值。 提供您自己的繫結邏輯,並透過 使用轉接程式
設定屬性值
每當繫結值變更時,產生的繫結類別都必須呼叫 setter 方法。您可以讓資料繫結 程式庫會自動決定方法,或者您也可以明確宣告 方法,或是提供自訂邏輯來選取方法。
自動選取方法
針對名為 example
的屬性,程式庫會自動尋找該方法
可接受相容類型做為引數的 setExample(arg)
。命名空間
將不會列入考量。只會使用屬性名稱和類型
可考慮使用這個選項
以 android:text="@{user.name}"
運算式為例,
尋找 setText(arg)
方法,該方法可接受由
user.getName()
。如果 user.getName()
的傳回類型為 String
,
程式庫會尋找可接受 String
引數的 setText()
方法。如果
運算式會傳回 int
,程式庫會搜尋 setText()
方法,
接受 int
引數。運算式必須傳回正確的類型。你可以
然後轉換傳回值
即使指定名稱的屬性不存在,資料繫結也能正常運作。你可以
使用資料繫結建立任何 setter 屬性。例如:
類別
DrawerLayout
敬上
沒有屬性,但具有大量設定器以下版面配置
會自動使用
setScrimColor(int)
敬上
和
addDrawerListener(DrawerListener)
。
做為 app:scrimColor
和 app:drawerListener
的 setter 方法
屬性來操作:
<androidx.drawerlayout.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
指定自訂方法名稱
部分屬性的 setter 名稱與名稱不符。在這種情況下,
屬性則可使用
BindingMethods
敬上
註解。註解會與類別搭配使用,且可包含多個
BindingMethod
敬上
註解,每個重新命名的方法各有一個。繫結方法是一種註解
您可以新增到應用程式的任何類別中。
在以下範例中,android:tint
屬性與
setImageTintList(ColorStateList)
方法,而非使用 setTint()
方法:
Kotlin
@BindingMethods(value = [ BindingMethod( type = android.widget.ImageView::class, attribute = "android:tint", method = "setImageTintList")])
Java
@BindingMethods({ @BindingMethod(type = "android.widget.ImageView", attribute = "android:tint", method = "setImageTintList"), })
一般而言,您不需要在 Android 架構類別中重新命名 setter。 屬性的值為 尋找相符的方法
提供自訂邏輯
部分屬性需要自訂繫結邏輯。舉例來說,
android:paddingLeft
屬性的 setter。而是改為提供 setPadding(left,
top, right, bottom)
方法。靜態繫結轉接器方法
BindingAdapter
註解可讓您自訂屬性的 setter 呼叫方式。
Android 架構類別的屬性已有 BindingAdapter
註解。以下範例顯示
paddingLeft
屬性:
Kotlin
@BindingAdapter("android:paddingLeft") fun setPaddingLeft(view: View, padding: Int) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()) }
Java
@BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int padding) { view.setPadding(padding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); }
參數類型相當重要。第一個參數會決定 與屬性相關聯的檢視畫面。第二個參數會決定 指定屬性的繫結運算式所接受的類型。
繫結轉接器也可用於其他自訂類型。例如: 可從背景工作執行緒呼叫自訂載入器來載入圖片。
你也可以讓轉接程式接收多個屬性,如 範例:
Kotlin
@BindingAdapter("imageUrl", "error") fun loadImage(view: ImageView, url: String, error: Drawable) { Picasso.get().load(url).error(error).into(view) }
Java
@BindingAdapter({"imageUrl", "error"}) public static void loadImage(ImageView view, String url, Drawable error) { Picasso.get().load(url).error(error).into(view); }
您可以在版面配置中使用轉接器,如以下範例所示。注意事項
@drawable/venueError
參照應用程式中的資源。在
具有 @{}
的資源可讓其成為有效的繫結運算式。
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
如果 imageUrl
和 error
用於
ImageView
物件,imageUrl
是
字串,而 error
是
Drawable
。如果您希望
設定任何屬性時要呼叫的轉接器,請設定選用的
requireAll
敬上
至 false
的轉接程式標記,如以下範例所示:
Kotlin
@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false) fun setImageUrl(imageView: ImageView, url: String?, placeHolder: Drawable?) { if (url == null) { imageView.setImageDrawable(placeholder); } else { MyImageLoader.loadInto(imageView, url, placeholder); } }
Java
@BindingAdapter(value={"imageUrl", "placeholder"}, requireAll=false) public static void setImageUrl(ImageView imageView, String url, Drawable placeHolder) { if (url == null) { imageView.setImageDrawable(placeholder); } else { MyImageLoader.loadInto(imageView, url, placeholder); } }
繫結轉接器方法可以擷取處理常式中的舊值。方法 採用新舊值時,必須先宣告屬性的所有舊值。 後面接著新的值,如以下範例所示:
Kotlin
@BindingAdapter("android:paddingLeft") fun setPaddingLeft(view: View, oldPadding: Int, newPadding: Int) { if (oldPadding != newPadding) { view.setPadding(newPadding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()) } }
Java
@BindingAdapter("android:paddingLeft") public static void setPaddingLeft(View view, int oldPadding, int newPadding) { if (oldPadding != newPadding) { view.setPadding(newPadding, view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom()); } }
事件處理常式只能與具有 1 個類別的介面或抽象類別搭配使用 抽象方法,如以下範例所示:
Kotlin
@BindingAdapter("android:onLayoutChange") fun setOnLayoutChangeListener( view: View, oldValue: View.OnLayoutChangeListener?, newValue: View.OnLayoutChangeListener? ) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (oldValue != null) { view.removeOnLayoutChangeListener(oldValue) } if (newValue != null) { view.addOnLayoutChangeListener(newValue) } } }
Java
@BindingAdapter("android:onLayoutChange") public static void setOnLayoutChangeListener(View view, View.OnLayoutChangeListener oldValue, View.OnLayoutChangeListener newValue) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (oldValue != null) { view.removeOnLayoutChangeListener(oldValue); } if (newValue != null) { view.addOnLayoutChangeListener(newValue); } } }
在版面配置中使用這個事件處理常式,如下所示:
<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/>
如果事件監聽器有多個方法,必須分割成多個事件監聽器。
例如:
View.OnAttachStateChangeListener
敬上
有兩種方法:
onViewAttachedToWindow(View)
。
和
onViewDetachedFromWindow(View)
。
程式庫提供兩個介面,可區分屬性和處理常式
:
Kotlin
// Translation from provided interfaces in Java: @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) interface OnViewDetachedFromWindow { fun onViewDetachedFromWindow(v: View) } @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) interface OnViewAttachedToWindow { fun onViewAttachedToWindow(v: View) }
Java
@TargetApi(VERSION_CODES.HONEYCOMB_MR1) public interface OnViewDetachedFromWindow { void onViewDetachedFromWindow(View v); } @TargetApi(VERSION_CODES.HONEYCOMB_MR1) public interface OnViewAttachedToWindow { void onViewAttachedToWindow(View v); }
由於變更一個事件監聽器會影響另一個事件監聽器,因此您需要有一個轉接程式
分別適用於任一屬性或兩者。你可以在以下位置將requireAll
設為false
:
註解,指出並非每項屬性都必須指派繫結
運算式,如以下範例所示:
Kotlin
@BindingAdapter( "android:onViewDetachedFromWindow", "android:onViewAttachedToWindow", requireAll = false ) fun setListener(view: View, detach: OnViewDetachedFromWindow?, attach: OnViewAttachedToWindow?) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { val newListener: View.OnAttachStateChangeListener? newListener = if (detach == null && attach == null) { null } else { object : View.OnAttachStateChangeListener { override fun onViewAttachedToWindow(v: View) { attach.onViewAttachedToWindow(v) } override fun onViewDetachedFromWindow(v: View) { detach.onViewDetachedFromWindow(v) } } } val oldListener: View.OnAttachStateChangeListener? = ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener) if (oldListener != null) { view.removeOnAttachStateChangeListener(oldListener) } if (newListener != null) { view.addOnAttachStateChangeListener(newListener) } } }
Java
@BindingAdapter({"android:onViewDetachedFromWindow", "android:onViewAttachedToWindow"}, requireAll=false) public static void setListener(View view, OnViewDetachedFromWindow detach, OnViewAttachedToWindow attach) { if (VERSION.SDK_INT >= VERSION_CODES.HONEYCOMB_MR1) { OnAttachStateChangeListener newListener; if (detach == null && attach == null) { newListener = null; } else { newListener = new OnAttachStateChangeListener() { @Override public void onViewAttachedToWindow(View v) { if (attach != null) { attach.onViewAttachedToWindow(v); } } @Override public void onViewDetachedFromWindow(View v) { if (detach != null) { detach.onViewDetachedFromWindow(v); } } }; } OnAttachStateChangeListener oldListener = ListenerUtil.trackListener(view, newListener, R.id.onAttachStateChangeListener); if (oldListener != null) { view.removeOnAttachStateChangeListener(oldListener); } if (newListener != null) { view.addOnAttachStateChangeListener(newListener); } } }
上述範例稍有複雜,因為
View
類別會使用
addOnAttachStateChangeListener()
。
和
removeOnAttachStateChangeListener()
而不是 setter 方法
OnAttachStateChangeListener
。
android.databinding.adapters.ListenerUtil
類別能協助追蹤這些管道
事件監聽器,以便在繫結轉接器中移除這些事件。
物件轉換
自動轉換物件
從繫結傳回 Object
時
運算式,程式庫會選取用來設定
資源。Object
會轉換為所選方法的參數類型。這個
透過使用 GCP 控制台
ObservableMap
類別
儲存資料,如以下範例所示:
<TextView
android:text='@{userMap["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
運算式中的 userMap
物件會傳回值,此值會自動
會轉換為在 setText(CharSequence)
方法中找到的參數類型
設定 android:text
屬性的值。如果參數類型為
不明確,會在運算式中轉換傳回類型。
自訂轉換
在某些情況下,不同類型需要自訂轉換。適用對象
例如,檢視區塊的 android:background
屬性預期有 Drawable
,但
指定的 color
值是整數。以下範例顯示
屬性為 Drawable
,但改為提供整數:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
當預期內傳回 Drawable
且傳回整數時,請轉換 int
至 ColorDrawable
。
如要執行轉換,請搭配
BindingConversion
敬上
註解中,如下所示:
Kotlin
@BindingConversion fun convertColorToDrawable(color: Int) = ColorDrawable(color)
Java
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
不過,繫結運算式中提供的值類型必須一致。 您不能在相同運算式中使用不同的類型,如下所示 範例:
// The @drawable and @color represent different value types in the same
// expression, which causes a build error.
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
其他資源
如要進一步瞭解資料繫結,請參閱下列資源。
範例
程式碼研究室
網誌文章
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- 資料繫結程式庫
- 版面配置與繫結的運算式
- 檢視區塊繫結