J'ai réussi à lier spinner à ArrayList
de objects
, maintenant je dois faire en sorte que lorsque vous sélectionnez un élément de spinner, il reflète à ViewModel
( setter est appelé et définit la valeur d'une variable sur laquelle l'index sélectionné est dans spinner )
J'ai réussi à faire fonctionner l'inverse, la valeur de viewmodel
est reflétée à view
( comme ceci Comment utiliser DataBindingUtil avec un spinner Android?).
xml pertinent
<data>
<variable
name="spinnerList"
type="com.example.root.proj.viewmodels.MonumentTypeVMList"/>
</data>
<Spinner
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
bind:spinnerbind="@{spinnerList.list}"
bind:selection="@{spinnerList.selection}"
></Spinner>
reliure personnalisée
@BindingAdapter("bind:selection")
public static void bindSelection(Spinner spinner, int position) {
spinner.setSelection(position);
}
Une solution encore plus simple (à mon avis) est présentée dans cette question , la clé étant l'utilisation de l'attribut selectedItemPostion de Spinner qui ne figure pas dans le code inclus dans la question mais dans le rapport. qu'il se lie à:
Android:selectedItemPosition="@={model.position}"
J'ai utilisé l'approche ci-dessus avec succès. Cela nécessite de faire le mappage entre les positions et les éléments réels de la liste de sélection, mais je devais le faire pour mon cas d'utilisation de toute façon.
Quasiment la même chose que la réponse d'Ajit mais avec Android: des entrées au lieu de lier un adaptateur.
<Android.support.v7.widget.AppCompatSpinner
Android:id="@+id/typeSpinner"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:entries="@{vehicle.types}"
Android:selectedItemPosition="@={vehicle.selectedTypePosition}">
Puis ma classe observable
@InverseBindingMethods({
@InverseBindingMethod(type = AppCompatSpinner.class, attribute = "Android:selectedItemPosition"),
})
class Vehicle extends BaseObservable {
String[] types = getResources().getStringArray(R.array.service_types);
String type = null;
@Bindable
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
notifyPropertyChanged(BR.type);
}
Integer selectedTypePosition = 0;
@Bindable
public Integer getSelectedTypePosition() {
return selectedTypePosition;
}
public void setSelectedTypePosition(Integer selectedTypePosition) {
this.selectedTypePosition = selectedTypePosition;
type = types[selectedTypePosition];
}
@BindingAdapter("selectedItemPositionAttrChanged")
void setSelectedItemPositionListener(AppCompatSpinner view, final InverseBindingListener selectedItemPositionChange) {
if (selectedItemPositionChange == null) {
view.setOnItemSelectedListener(null);
} else {
view.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
selectedItemPositionChange.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
}
@InverseBindingAdapter(attribute = "selectedItemPosition")
Integer getSelectedItemPosition(AppCompatSpinner spinner) {
return spinner.getSelectedItemPosition();
}
}
Cela a simplifié mon implémentation et ne l’a pas testé. Devrait fonctionner si ...
Vous pouvez utiliser Inverse Binding pour y parvenir. Vous devrez définir deux liaisons personnalisées.
Pour obtenir la valeur sélectionnée du compteur, ajoutez cette méthode à vos liaisons personnalisées.
@InverseBindingAdapter(attribute = "selection", event = "selectionAttrChanged")
public static String getSelectedValue(AdapterView view) {
return (String) view.getSelectedItem();
}
Pour déclencher un événement quand une nouvelle valeur est sélectionnée dans l'utilisation de spinner
@BindingAdapter(value = {"selection", "selectionAttrChanged", "adapter"}, requireAll = false)
public static void setAdapter(AdapterView view, String newSelection, final InverseBindingListener bindingListener, ArrayAdapter adapter) {
view.setAdapter(adapter);
view.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
bindingListener.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
//Nothing
}
});
if (newSelection != null) {
int pos = ((ArrayAdapter) view.getAdapter()).getPosition(newSelection);
view.setSelection(pos);
}
}
Maintenant, dans votre fichier de mise en page, utilisez simplement la liaison ci-dessus en tant que:
<Spinner
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:adapter="@{AdapterFactory.getAdapter(context)}"
app:selection="@={model.selectedValue}"/>
Mettre en œuvre une liaison à double sens pour Spinner
1) Utilisez un attribut personnalisé et ajoutez une expression de liaison bidirectionnelle pour lier la propriété du modèle de données à l'attribut personnalisé. Dans le code ci-dessous, bind: paymentMode est un attribut personnalisé.
<Android.support.v7.widget.AppCompatSpinner
. . .
bind:pmtOpt="@={accountSettings.defaultPaymentOption}"
app:adapter="@{spinAdapter}" />
2) Ensuite, pour fournir le comportement ou la méthode de définition à utiliser lors de la liaison de données (modèle de données vers spinner) pour cet attribut, BindingAdapter doit être défini. Lorsqu’une liaison est établie, nous devons définir la valeur sélectionnée par défaut et ajouter l’élément écouteur sélectionné à spinner et dans l’écouteur lorsqu’un événement de sélection d’élément se produit, nous devons informer le cadre de liaison de données pour capturer la valeur en utilisant InverseBindingListener pour initier la liaison inverse.
@BindingAdapter(value = {"bind:paymentMode",
"bind:paymentModeAttrChanged"}, requireAll = false)
public static void setPaymentMode(final AppCompatSpinner spinner,
final String selectedPmtMode,
final InverseBindingListener changeListener) {
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
changeListener.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
changeListener.onChange();
}
});
spinner.setSelection(getIndexOfItem(spinner, selectedPmtMode));
}
3) Définissez l’adaptateur de liaison inverse («spinner to model») utilisé par la structure pour capturer la valeur sélectionnée par l’utilisateur et la définir comme modèle de données. Ceci est appelé lorsque InverseBindingListener reçoit une notification.
@InverseBindingAdapter(attribute = "bind:paymentMode",
event = "bind:paymentModeAttrChanged")
public static String getPaymentMode(final AppCompatSpinner spinner) {
return (String)spinner.getSelectedItem();
}
Pour plus d'informations sur la liaison de données et l'implémentation de la liaison bidirectionnelle spinner, voir http://www.zoftino.com/Android-data-binding-library-tutorial