Bindungsadapter sind für die Durchführung der entsprechenden Framework-Aufrufe an
Werte festlegen. Ein Beispiel ist das Festlegen eines Eigenschaftswerts, z. B. das Aufrufen der
setText()
-Methode. Anderes
ist das Festlegen eines Event-Listeners, z. B. das Aufrufen der
setOnClickListener()
.
Mit der Datenbindungsbibliothek können Sie die aufgerufene Methode angeben, um einen Wert festzulegen. stellen Sie Ihre eigene Bindungslogik bereit und geben Sie den Typ des zurückgegebenen Objekts an, mit Adaptern.
Attributwerte festlegen
Wenn sich ein Grenzwert ändert, muss die generierte Bindungsklasse einen Setter aufrufen für die Ansicht mit dem Bindungsausdruck. Sie können die Datenbindung Die Methode wird automatisch von der Bibliothek festgelegt. Alternativ können Sie die Methode explizit deklarieren oder benutzerdefinierte Logik zur Auswahl einer Methode bereitstellen.
Automatische Methodenauswahl
Für ein Attribut namens example
sucht die Bibliothek automatisch nach der Methode
setExample(arg)
, die kompatible Typen als Argument akzeptiert. Namespace
des Attributs nicht berücksichtigt. Nur Attributname und -typ werden verwendet
wenn Sie nach einer Methode suchen.
Mit dem Ausdruck android:text="@{user.name}"
würde die Bibliothek beispielsweise
sucht nach einer setText(arg)
-Methode, die den von
user.getName()
Wenn der Rückgabetyp von user.getName()
String
ist, gibt der Wert
sucht nach einer setText()
-Methode, die ein String
-Argument akzeptiert. Wenn die
wenn der Ausdruck ein int
zurückgibt, sucht die Bibliothek nach einer setText()
-Methode,
akzeptiert ein int
-Argument. Der Ausdruck muss den richtigen Typ zurückgeben. Sie können
wandeln Sie den Rückgabewert gegebenenfalls um.
Die Datenbindung funktioniert auch dann, wenn kein Attribut mit dem angegebenen Namen vorhanden ist. Sie können
mithilfe von Datenbindung Attribute
für beliebige Setter erstellen. Zum Beispiel hat der Support
Klasse
DrawerLayout
hat keine Attribute, aber viele Setter. Das folgende Layout
verwendet automatisch die
setScrimColor(int)
und
addDrawerListener(DrawerListener)
als Setter für app:scrimColor
und app:drawerListener
Attribute:
<androidx.drawerlayout.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
Geben Sie einen benutzerdefinierten Methodennamen an
Einige Attribute haben Setter, die nicht namentlich zugeordnet werden. In diesen Fällen wird ein
kann mithilfe der Methode
BindingMethods
. Die Annotation wird mit einer Klasse verwendet und kann mehrere
BindingMethod
-Annotationen, eine für jede umbenannte Methode. Bindungsmethoden sind Annotationen,
die Sie jedem Kurs in Ihrer App hinzufügen können.
Im folgenden Beispiel wird das Attribut android:tint
mit dem Parameter
setImageTintList(ColorStateList)
und nicht mit der Methode 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"), })
Normalerweise müssen Sie Setter in Android-Framework-Klassen nicht umbenennen. Die -Attribute sind bereits mithilfe der Namenskonvention implementiert, um automatisch Abgleichmethoden suchen.
Benutzerdefinierte Logik bereitstellen
Einige Attribute erfordern eine benutzerdefinierte Bindungslogik. Zum Beispiel gibt es keine zugehörigen
Setter für das Attribut android:paddingLeft
. Stattdessen wird die Methode setPadding(left,
top, right, bottom)
bereitgestellt. Eine statische Bindungsadaptermethode mit
BindingAdapter
Mit Annotation können Sie anpassen, wie ein Setter für ein Attribut aufgerufen wird.
Die Attribute der Android-Framework-Klassen haben bereits BindingAdapter
Anmerkungen. Das folgende Beispiel zeigt den Bindungsadapter für die
Attribut 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()); }
Die Parametertypen sind wichtig. Der erste Parameter bestimmt die Art der die mit dem Attribut verknüpfte Ansicht. Der zweite Parameter bestimmt, Der im Bindungsausdruck für das jeweilige Attribut akzeptierte Typ.
Bindungsadapter sind auch für andere Arten der Anpassung nützlich. Beispiel: Ein benutzerdefiniertes Ladeprogramm kann aus einem Worker-Thread aufgerufen werden, um ein Image zu laden.
Sie können auch Adapter verwenden, die mehrere Attribute erhalten, wie in den folgendes Beispiel:
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); }
Sie können den Adapter in Ihrem Layout verwenden, wie im folgenden Beispiel gezeigt. Hinweis
dass @drawable/venueError
auf eine Ressource in Ihrer Anwendung verweist. Um die
Ressource mit @{}
macht sie zu einem gültigen Bindungsausdruck.
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
Der Adapter wird aufgerufen, wenn imageUrl
und error
für eine
ImageView
-Objekt, imageUrl
ist ein
String und error
ist ein
Drawable
Bei Bedarf
Den Adapter, der aufgerufen werden soll, wenn eines der Attribute festgelegt ist, legen Sie den optionalen
requireAll
des Adapters auf false
, wie im folgenden Beispiel gezeigt:
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); } }
Bindungsadaptermethoden können die alten Werte in ihren Handlern verwenden. Methode Wenn Sie alte und neue Werte übernehmen, müssen zuerst alle alten Werte für die Attribute deklariert werden. gefolgt von den neuen Werten, wie im folgenden Beispiel gezeigt:
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()); } }
Event-Handler können nur mit Schnittstellen oder abstrakten Klassen mit einer abstrakte Methode verwenden, wie im folgenden Beispiel gezeigt:
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); } } }
Verwenden Sie diesen Ereignis-Handler in Ihrem Layout wie folgt:
<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/>
Wenn ein Listener mehrere Methoden hat, muss er in mehrere Listener aufgeteilt werden.
Beispiel:
View.OnAttachStateChangeListener
verfügt über zwei Methoden:
onViewAttachedToWindow(View)
und
onViewDetachedFromWindow(View)
Die Bibliothek bietet zwei Schnittstellen zur Unterscheidung der Attribute und Handler.
für sie:
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); }
Da sich Änderungen an einem Listener auf den anderen auswirken können, benötigen Sie einen Adapter,
funktioniert für eines der Attribute oder für beide. Sie können requireAll
auf false
setzen in
Die Annotation, die angibt, dass nicht jedem Attribut eine Bindung zugewiesen werden muss
wie im folgenden Beispiel gezeigt:
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); } } }
Das obige Beispiel ist etwas kompliziert, da die
Für die Klasse View
wird die Methode
addOnAttachStateChangeListener()
und
removeOnAttachStateChangeListener()
anstelle einer Setter-Methode für
OnAttachStateChangeListener
Mit der Klasse android.databinding.adapters.ListenerUtil
behältst du den Überblick.
Listener, sodass sie aus dem Bindungsadapter entfernt werden können.
Objekt-Conversions
Automatische Objektkonvertierung
Wenn ein Object
von einer Bindung zurückgegeben wird
verwendet, wählt die Bibliothek die Methode aus, mit der der Wert des
Property. Object
wird in einen Parametertyp der ausgewählten Methode umgewandelt. Dieses
in Apps mit der Funktion
ObservableMap
Kurs für
Daten speichern, wie im folgenden Beispiel gezeigt:
<TextView
android:text='@{userMap["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Das userMap
-Objekt im Ausdruck gibt einen Wert zurück, der automatisch
in den Parametertyp umwandeln, der in der Methode setText(CharSequence)
für
Legen Sie den Wert des Attributs android:text
fest. Wenn der Parametertyp
nicht eindeutig ist, wandeln Sie den Rückgabetyp in den Ausdruck um.
Benutzerdefinierte Conversions
In einigen Situationen ist zwischen bestimmten Typen eine benutzerdefinierte Conversion erforderlich. Für
Beispiel: Das Attribut android:background
eines Aufrufs erwartet ein Drawable
, aber
der angegebene Wert für color
eine Ganzzahl ist. Das folgende Beispiel zeigt eine
Attribut, das ein Drawable
erwartet, aber stattdessen eine Ganzzahl angegeben wird:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Immer wenn eine Drawable
erwartet und eine Ganzzahl zurückgegeben wird, wandeln Sie int
um
in ColorDrawable
.
Verwenden Sie für die Konvertierung eine statische Methode mit einem
BindingConversion
wie folgt an:
Kotlin
@BindingConversion fun convertColorToDrawable(color: Int) = ColorDrawable(color)
Java
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
Die im Bindungsausdruck angegebenen Werttypen müssen jedoch einheitlich sein. Sie können in einem Ausdruck nicht verschiedene Typen verwenden, wie im Folgenden gezeigt: Beispiel:
// 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"/>
Weitere Informationen
Weitere Informationen zur Datenbindung finden Sie in den folgenden Ressourcen.
Produktproben
Codelabs
Blogposts
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Datenbindungsbibliothek
- Layouts und Bindungsausdrücke
- Bindung ansehen