web-dev-qa-db-fra.com

comment lier 2 voies spinner valeur sélectionnée à valeur dans une liste

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);
}
7
dzingiskan

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.

6
Maks

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 ...

6
luca992

Vous pouvez utiliser Inverse Binding pour y parvenir. Vous devrez définir deux liaisons personnalisées.

  1. Pour obtenir la dernière valeur de la roulette et la définir dans le modèle.
  2. Déclenche un événement lorsqu'une nouvelle valeur est sélectionnée dans le compteur.

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}"/>
3
Ajit Singh

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

0
Arnav Rao