バインディング アダプターは、適切なフレームワーク呼び出しを行う役割を担います。
設定します。たとえば、
setText()
メソッドを使用します。その他
たとえば、イベント リスナーの設定です。
setOnClickListener()
メソッドを呼び出します。
データ バインディング ライブラリを使用すると、値を設定するために呼び出されるメソッドを指定できます。 独自のバインディング ロジックを提供し、返されるオブジェクトの型を 使用できます。
属性値を設定する
バインド値が変更されるたびに、生成されたバインディング クラスでセッターを呼び出す必要がある メソッドをバインディング式でビューに適用します。データ バインディングでは、 このメソッドは、ライブラリが自動的に決定しますが、 メソッドを選択するためのカスタム ロジックを指定できます。
メソッドの自動選択
example
という名前の属性の場合、ライブラリは自動的にメソッドを検索します。
互換性のある型を引数として受け入れる setExample(arg)
。Namespace
考慮されません。属性名とタイプのみが使用されます。
メソッドを検索する際に表示されます。
たとえば、android:text="@{user.name}"
式の場合、ライブラリは
返された型を受け入れる setText(arg)
メソッドを探します。
user.getName()
。user.getName()
の戻り値の型が String
の場合、
ライブラリが、String
引数を受け入れる setText()
メソッドを探します。もし
式が int
を返す場合、ライブラリは、次の setText()
メソッドを検索します。
int
引数を受け入れます。この式は正しい型を返す必要があります。Google Chat では
必要に応じて戻り値をキャストします。
データ バインディングは、指定した名前の属性が存在しない場合でも機能します。Google Chat では
データ バインディングを使用してセッターの属性を作成する。たとえば、
クラス
DrawerLayout
属性はありませんが、多くのセッターがあります。次のレイアウト
自動的に
setScrimColor(int)
および
addDrawerListener(DrawerListener)
メソッド(app:scrimColor
と app:drawerListener
のセッターとして)
それぞれ次の属性があります。
<androidx.drawerlayout.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
カスタムのメソッド名を指定する
一部の属性には、名前で照合できないセッターがあります。このような場合、
属性をセッターに関連付けるには、
BindingMethods
アノテーション。アノテーションはクラスで使用され、複数のアノテーションを含めることができます。
BindingMethod
名前が変更されたメソッドごとに 1 つずつです。バインディング メソッドは、
アプリの任意のクラスに追加できます
次の例では、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 フレームワーク クラスのセッターの名前を変更する必要はありません。「 各属性は、名前規則を使用して自動的に実装され、 一致するメソッドを検索します。
カスタム ロジックを提供する
属性によっては、カスタムのバインディング ロジックが必要な場合もあります。たとえば、1 つのテーブルに
android:paddingLeft
属性のセッター。その代わり、setPadding(left,
top, right, bottom)
メソッドが提供されています。静的バインディング アダプター メソッド
BindingAdapter
アノテーションを使用すると、属性のセッターの呼び出し方法をカスタマイズできます。
Android フレームワーク クラスの属性には、すでに BindingAdapter
が含まれています。
アノテーション。次の例は、Cloud Storage バケットのバインディング アダプターを
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()); }
パラメータの型は重要です。最初のパラメータで ビューを定義します。2 番目のパラメータで、 指定された属性のバインディング式で受け入れられる型。
バインディング アダプターは、他の種類のカスタマイズでも有用です。たとえば ワーカー スレッドからカスタム ローダーを呼び出して、画像を読み込むことができます。
また、次に示すように、複数の属性を受け取るアダプターを使用することもできます。 次の例をご覧ください。
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()); } }
イベント ハンドラをインターフェースまたは抽象クラスと併用できるのは、 抽象化メソッドを使用します。
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
には、次の 2 つのメソッドがあります。
onViewAttachedToWindow(View)
および
onViewDetachedFromWindow(View)
。
ライブラリには、属性とハンドラを区別するための 2 つのインターフェースが用意されています。
説明します。
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()
メソッドをセッター メソッドの代わりに使用し、
OnAttachStateChangeListener
。
android.databinding.adapters.ListenerUtil
クラスは、これらのイベントを追跡するのに役立ちます。
バインディング アダプターで削除できます。
オブジェクトの変換
オブジェクトの自動変換
Object
がバインディングから返された場合
式を指定すると、ライブラリは、変数の値を
プロパティです。Object
は、選択されたメソッドのパラメータ型にキャストされます。この
動作は、
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"/>
参考情報
データ バインディングの詳細については、次のリソースをご覧ください。
サンプル
Codelab
ブログ投稿
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- データ バインディング ライブラリ
- レイアウトとバインディング式
- ビュー バインディング