Les adaptateurs de liaison sont chargés d'effectuer les appels de framework appropriés
définir des valeurs. Vous pouvez, par exemple, définir une valeur de propriété,
setText()
. Autre
consiste, par exemple, à définir un écouteur d'événements,
setOnClickListener()
.
La bibliothèque Data Binding vous permet de spécifier la méthode appelée pour définir une valeur, fournir votre propre logique de liaison et spécifier le type de l'objet renvoyé à l'aide d'adaptateurs.
Définir les valeurs des attributs
Chaque fois qu'une valeur liée change, la classe de liaison générée doit appeler un setter sur la vue avec l'expression de liaison. Vous pouvez laisser la liaison de données la bibliothèque détermine automatiquement la méthode, ou vous pouvez déclarer explicitement ou fournissez une logique personnalisée pour sélectionner une méthode.
Sélection automatique de la méthode
Pour un attribut nommé example
, la bibliothèque trouve automatiquement la méthode
setExample(arg)
qui accepte les types compatibles comme argument. Espace de noms
de l'attribut n'est pas prise en compte. Seuls le nom et le type de l'attribut sont utilisés
lorsque vous recherchez une méthode.
Par exemple, pour l'expression android:text="@{user.name}"
, la bibliothèque
recherche une méthode setText(arg)
qui accepte le type renvoyé par
user.getName()
Si le type renvoyé de user.getName()
est String
,
recherche une méthode setText()
qui accepte un argument String
. Si le
renvoie un int
, la bibliothèque recherche une méthode setText()
qui
accepte un argument int
. L'expression doit renvoyer le type correct. Vous pouvez
si nécessaire, castez la valeur renvoyée.
La liaison de données fonctionne même si aucun attribut du nom donné n'existe. Vous pouvez
créer des attributs pour n'importe quel setter en utilisant la liaison de données. Par exemple, l'assistance
cours
DrawerLayout
n'a pas d'attributs, mais il a beaucoup de setters. La mise en page suivante
utilise automatiquement
setScrimColor(int)
et
addDrawerListener(DrawerListener)
comme setter pour app:scrimColor
et app:drawerListener
, respectivement:
<androidx.drawerlayout.widget.DrawerLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:scrimColor="@{@color/scrim}"
app:drawerListener="@{fragment.drawerListener}">
Spécifier un nom de méthode personnalisé
Certains attributs ont des setters qui ne correspondent pas par nom. Dans ces situations, un
peut être associé au setter à l'aide du
BindingMethods
. L'annotation est utilisée avec une classe et peut contenir plusieurs
BindingMethod
des annotations, une pour chaque méthode renommée. Les méthodes de liaison sont des annotations
que vous pouvez ajouter à n'importe quel cours de votre application.
Dans l'exemple suivant, l'attribut android:tint
est associé au
setImageTintList(ColorStateList)
, mais pas avec la méthode 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"), })
En règle générale, vous n'avez pas besoin de renommer les setters dans les classes du framework Android. La sont déjà mis en œuvre selon la convention de nommage trouver des méthodes de correspondance.
Fournir une logique personnalisée
Certains attributs nécessitent une logique de liaison personnalisée. Par exemple, il n'existe aucun
Setter de l'attribut android:paddingLeft
À la place, la méthode setPadding(left,
top, right, bottom)
est fournie. Une méthode d'adaptateur de liaison statique avec
le BindingAdapter
vous permet de personnaliser l'appel d'un setter pour un attribut.
Les attributs des classes du framework Android disposent déjà de BindingAdapter
. L'exemple suivant montre l'adaptateur de liaison pour
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()); }
Les types de paramètres sont importants. Le premier paramètre détermine le type la vue associée à l'attribut. Le deuxième paramètre détermine Type accepté dans l'expression de liaison de l'attribut donné.
Les adaptateurs de liaison sont également utiles pour d'autres types de personnalisation. Par exemple : Un chargeur personnalisé peut être appelé à partir d'un thread de nœud de calcul pour charger une image.
Vous pouvez également avoir des adaptateurs qui reçoivent plusieurs attributs, comme indiqué dans le l'exemple suivant:
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); }
Vous pouvez utiliser l'adaptateur dans votre mise en page, comme illustré dans l'exemple suivant. Remarque
que @drawable/venueError
fait référence à une ressource de votre application. Autour du
avec @{}
en fait une expression de liaison valide.
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
L'adaptateur est appelé si imageUrl
et error
sont utilisés pour une
objet ImageView
, imageUrl
est
chaîne, et error
est une
Drawable
. Si vous voulez
l'adaptateur à appeler lorsque l'un des attributs est défini, définissez le paramètre
requireAll
de l'adaptateur à false
, comme illustré dans l'exemple suivant:
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); } }
Les méthodes d'adaptateur de liaison peuvent utiliser les anciennes valeurs dans leurs gestionnaires. Une méthode l'utilisation des anciennes et des nouvelles valeurs doit d'abord déclarer toutes les anciennes valeurs pour les attributs, suivi des nouvelles valeurs, comme illustré dans l'exemple suivant:
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()); } }
Les gestionnaires d'événements ne peuvent être utilisés qu'avec des interfaces ou des classes abstraites avec une seule méthode abstraite, comme illustré dans l'exemple suivant:
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); } } }
Utilisez ce gestionnaire d'événements dans votre mise en page comme suit:
<View android:onLayoutChange="@{() -> handler.layoutChanged()}"/>
Lorsqu'un écouteur comporte plusieurs méthodes, il doit être divisé en plusieurs écouteurs.
Par exemple :
View.OnAttachStateChangeListener
propose deux méthodes:
onViewAttachedToWindow(View)
et
onViewDetachedFromWindow(View)
La bibliothèque fournit deux interfaces pour différencier les attributs et les gestionnaires
pour eux:
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); }
Étant donné que la modification d'un écouteur peut affecter l'autre, vous avez besoin d'un adaptateur qui
fonctionne pour l'un ou l'autre de ces attributs ou pour les deux. Vous pouvez définir requireAll
sur false
dans
Annotation permettant de spécifier qu'une liaison ne doit pas être attribuée à tous les attributs
, comme illustré dans l'exemple suivant:
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); } } }
L'exemple ci-dessus est un peu compliqué, car le
La classe View
utilise la
addOnAttachStateChangeListener()
et
removeOnAttachStateChangeListener()
au lieu d'une méthode setter pour
OnAttachStateChangeListener
.
La classe android.databinding.adapters.ListenerUtil
permet d'effectuer un suivi de ces éléments.
afin qu'ils puissent être supprimés de l'adaptateur de liaison.
Conversions d'objets
Conversion automatique d'objets
Lorsqu'un Object
est renvoyé par une liaison
, la bibliothèque sélectionne la méthode utilisée pour définir la valeur de la
. Object
est converti en type de paramètre de la méthode choisie. Ce
est pratique dans les applications qui utilisent
classe ObservableMap
pour
stocker des données, comme illustré dans l'exemple suivant:
<TextView
android:text='@{userMap["lastName"]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
L'objet userMap
de l'expression renvoie une valeur, qui est automatiquement
au type de paramètre trouvé dans la méthode setText(CharSequence)
utilisée pour
définissez la valeur de l'attribut android:text
. Si le type de paramètre est
ambigu, convertissez le type renvoyé dans l'expression.
Conversions personnalisées
Dans certains cas, une conversion personnalisée est requise entre des types spécifiques. Pour
Par exemple, l'attribut android:background
d'une vue attend un Drawable
, mais
la valeur color
spécifiée est un entier. L'exemple suivant illustre une
qui attend un Drawable
, mais un entier est fourni à la place:
<View
android:background="@{isError ? @color/red : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Chaque fois qu'une Drawable
est attendue et qu'un entier est renvoyé, convertissez l'int
à un ColorDrawable
.
Pour effectuer la conversion, utilisez une méthode statique avec une
BindingConversion
comme suit:
Kotlin
@BindingConversion fun convertColorToDrawable(color: Int) = ColorDrawable(color)
Java
@BindingConversion public static ColorDrawable convertColorToDrawable(int color) { return new ColorDrawable(color); }
Cependant, les types de valeurs fournis dans l'expression de liaison doivent être cohérents. Vous ne pouvez pas utiliser différents types dans la même expression, comme illustré ci-dessous Exemple:
// 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"/>
Ressources supplémentaires
Pour en savoir plus sur la liaison de données, consultez les ressources suivantes.
Exemples
Ateliers de programmation
Articles de blog
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Bibliothèque Data Binding
- Dispositions et expressions de liaison
- Liaison de vue