web-dev-qa-db-fra.com

Android spinner Data Binding en utilisant XML et afficher les valeurs sélectionnées

J'utilise la nouvelle liaison de données Android et cela fonctionne très bien. Je suis capable d'effectuer la liaison de données en utilisant EditText, TextView, Radio et checkbox. Maintenant, je ne suis pas capable de faire la liaison de données dans spinner.

Vous avez trouvé un indice dans le lien ci-dessous: Android spinner data binding with xml layout

Mais, toujours pas en mesure de trouver la solution. Vous devez également effectuer la liaison de données bidirectionnelle. Devrait refléter la valeur sélectionnée des données de rotation.

Quelqu'un peut-il s'il vous plaît me montrer avec un exemple?

Voici mon code xml:

<layout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/tools"
    xmlns:card_view="http://schemas.Android.com/apk/res-auto">

    <data>
        <import type="Android.view.View" />
        <variable
            name="viewModel"
            type="com.ViewModels.model" />
    </data>

     <Spinner
                    Android:id="@+id/assessmemt_spinner"
                    Android:layout_width="match_parent"
                    Android:layout_height="wrap_content"
                    Android:layout_alignParentRight="true"
                    Android:layout_margin="@dimen/carview_margin"
                    Android:layout_toRightOf="@+id/text_bp"
                    Android:drawSelectorOnTop="true"
                    Android:spinnerMode="dropdown"
                   Android:visibility="@{viewModel.type.equals(@string/spinner_type)?  View.VISIBLE : View.GONE}" />
</layout>

Voir le modèle:

 public class AssessmentGetViewModel {
    private String valueWidth;
    private ArrayList<String> values;
    private String type;
    public String getValueWidth() { return this.valueWidth; }
    public void setValueWidth(String valueWidth) { this.valueWidth = valueWidth; }
    public ArrayList<String> getvalues() { return this.values; }
    public void setvalues(ArrayList<String> values) { this.values = values; }
    public String gettype() { return this.type; }
    public void settype(String type) { this.type = type; }
    }
19
San Jaisy

J'ai trouvé quelque chose qui pourrait être utile mais ce n'est pas dans la documentation officielle pour la liaison de données bidirectionnelle.

1. '@ =' utilisation pour la liaison de données bidirectionnelle

2. La liaison de données personnalisée bidirectionnelle nécessite les annotations "BindingAdapter" et "InverseBindingAdapter" pour y parvenir.

Pour le premier élément, de nombreux blogueurs ont montré l'utilisation de "@ =" pour la liaison de données bidirectionnelle. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-Android/

Pour le second élément, comme @George Mound a répondu ici ( le curseur de texte d'édition est réinitialisé à gauche lorsque le texte par défaut d'edittext est une valeur flottante ), le texte d'édition peut être lié dans les deux sens à l'aide de l'annotation "BindingAdapter" et "InverseBindingAdapter" . 

En suivant les instructions, vous pouvez créer votre méthode de reliure bidirectionnelle pour spinner.

Tout d'abord, créez votre ViewModel ou utilisez Pojo

ViewModel

public class ViewModel {
    private ObservableField<String> text;
    public ViewModel() {
        text = new ObservableField<>();
    }
    public ObservableField<String> getText() {
        return text;
    }
}

Pojo

public class ViewModel {
    private String text;
    public String getText() {
        return text;
    }

    public void setText(String text)
    {
       this.text = text;
    }
}

Deuxièmement, ajoutez-le dans votre XML.

  <Android.support.v7.widget.AppCompatSpinner
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:entries="@array/days"
            bind:selectedValue="@={viewModel.text}"/>

Troisièmement, ajoutez votre liaisonUtil

public class SpinnerBindingUtil {

    @BindingAdapter(value = {"selectedValue", "selectedValueAttrChanged"}, requireAll = false)
    public static void bindSpinnerData(AppCompatSpinner pAppCompatSpinner, String newSelectedValue, final InverseBindingListener newTextAttrChanged) {
        pAppCompatSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                newTextAttrChanged.onChange();
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
        if (newSelectedValue != null) {
            int pos = ((ArrayAdapter<String>) pAppCompatSpinner.getAdapter()).getPosition(newSelectedValue);
            pAppCompatSpinner.setSelection(pos, true);
        }
    }
    @InverseBindingAdapter(attribute = "selectedValue", event = "selectedValueAttrChanged")
    public static String captureSelectedValue(AppCompatSpinner pAppCompatSpinner) {
        return (String) pAppCompatSpinner.getSelectedItem();
    }

}

Comme vous l'avez vu, il a utilisé "selectedValue" comme variable pour la valeur sélectionnée par défaut, mais que signifie "selectedValueAttrChanged"? Je pensais que celui-ci est délicat (je ne sais pas pourquoi il n'est pas nul quand il est appelé), il n'est pas nécessaire de l'ajouter au xml puisqu'il ne s'agit que du rappel pour l'écoute de l'élément modifié dans le compteur. Ensuite, vous définissez onItemSelectedListener et l'appelez la fonction InverseBindingListener onchange () (Documentation et exemple ici: https://developer.Android.com/reference/Android/databinding/InverseBindingAdapter.html ) L'événement par défaut sera "Android: textAttrChanged" et si vous souhaitez avoir une liaison bidirectionnelle personnalisée, inversebind, vous devez utiliser l'attribut avec le suffixe "AttrChanged".

La valeur par défaut pour event est le nom de l'attribut avec le suffixe "Attrchangé". Dans l'exemple ci-dessus, la valeur par défaut aurait été Android: textAttrChanged même s'il n'a pas été fourni.

Enfin, dans votre activité et votre string.xml

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityMainBinding lBinding = DataBindingUtil.inflate(LayoutInflater.from(this), R.layout.activity_main, null, false);
    mViewModel = new ViewModel();
    mViewModel.getText().set("Wednesday");
    lBinding.setViewModel(mViewModel);
    lBinding.setHandler(new Handler());
    setContentView(lBinding.getRoot());
}

string.xml

<array name="days">
    <item name="Mon">Monday</item>
    <item name="Tue">Tuesday</item>
    <item name="Wed">Wednesday</item>
</array>

Lorsque vous exécutez le code, "Mercredi" sera affiché comme valeur par défaut pour le compteur. J'espère que cela peut aider pour beaucoup de gens

22
Long Ranger

Vous pouvez le faire simplement avec onItemSelected et obtenir la position sélectionnée et le texte de l’article sélectionné.

1) ajoutez onItemSelected attribut à votre disque comme ci-dessous:

<Spinner
      Android:id="@+id/spinner"
      Android:layout_width="match_parent"
      Android:layout_height="wrap_content"
      Android:entries="@array/item_list"
      Android:onItemSelected="@{(parent,view,pos,id)->viewModel.onSelectItem(parent,view,pos,id)}"/>

2) maintenant vous devez ajouter cette méthode à votre viewModel :

public void onSelectItem(AdapterView<?> parent, View view, int pos, long id)
{
    //pos                                 get selected item position
    //view.getText()                      get lable of selected item
    //parent.getAdapter().getItem(pos)    get item by pos
    //parent.getAdapter().getCount()      get item count
    //parent.getCount()                   get item count
    //parent.getSelectedItem()            get selected item
    //and other...
}

tableau pourrait être quelque chose comme cela doit enregistrer dans values ​​/ item_list.xml :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <array name="item_list">
        <item>item1</item>
        <item>item2</item>
        <item>item3</item>
    </array>
</resources>

Lorsque la mise en page est dessinée, onItemSelected est appelé, vous pouvez définir la valeur initiale:

parent.setSelection(1); //1 is position of initializing value
8

Solution à 1 ligne

Android:selectedItemPosition="@={item.selectedItemPosition}"

C'est tout! Pas besoin de personnaliser BindingAdapter.

Spinner prend déjà en charge la liaison bidirectionnelle par les attributs selection et selectedItemPosition. Voir Documentation Android

Vous devez simplement utiliser la liaison à deux voies selectedItemPosition pour que changer sur spinner réfléchir sur votre champ modèle.

Exemple

Item.class

public class Item extends BaseObservable {
    private int selectedItemPosition;

    @Bindable
    public int getSelectedItemPosition() {
        return selectedItemPosition;
    }

    public void setSelectedItemPosition(int selectedItemPosition) {
        this.selectedItemPosition = selectedItemPosition;
        notifyPropertyChanged(BR.selectedItemPosition);
    }
}

activity_main.xml

<variable
    name="item"
    type="com.sample.data.Item"/>

<Android.support.v7.widget.AppCompatSpinner
    ...
    Android:entries="@array/items"
    Android:selectedItemPosition="@={item.selectedItemPosition}"
    >

MainActivity.Java

public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setItem(new Item());
        binding.getItem().setSelectedItemPosition(4); // this will change spinner selection.
        System.out.println(getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]);
    }
}

Si vous avez besoin d’obtenir un élément sélectionné de votre code à tout moment, utilisez cette commande.

binding.getItem().getSelectedItemPosition(); // get selected position
getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]) // get selected item

Définissez votre variable @Bindable si vous devez la modifier par programme. 

binding.getItem().setSelectedItemPosition(4);

Sinon, vous pouvez supprimer @Bindable et notifyPropertyChanged(BR.selectedItemPosition);.

Vous pouvez utiliser n'importe lequel de BaseObservable ou ObservableField ou Live Data. C'est à toi de decider. J'utilise BaseObservable parce que c'est très simple., étendez simplement BaseObservable et tous les champs sont maintenant observables.

3
Khemraj

Voir ma réponse pour obtenir la liaison de données la plus simple possible avec spinner. En effet, nous avons besoin d'un adaptateur pour effectuer d'autres tâches.

Le code XML est là.

Java:


    //  Data binding
        ActivityParentsRegBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_parents_reg);
        binding.setCities(ConstData.getCitiesList());
0
ForWebTech

@ Long Ranger J'aime beaucoup votre réponse, mais je pense qu'il y a quelque chose que nous devons faire pour rompre la boucle.

@BindingAdapter(value = {"bind:selectedValue", "bind:selectedValueAttrChanged"}, requireAll = false)
public static void bindSpinnerData(AppCompatSpinner pAppCompatSpinner, final String newSelectedValue, final InverseBindingListener newTextAttrChanged) {
    pAppCompatSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if(newSelectedValue != null && newSelectedValue.equals(parent.getSelectedItem())){
               return;
            }
            newTextAttrChanged.onChange();
        }
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
        }
    });
    if (newSelectedValue != null) {
        int pos = ((ArrayAdapter<String>) pAppCompatSpinner.getAdapter()).getPosition(newSelectedValue);
        pAppCompatSpinner.setSelection(pos, true);
    }
}
0
user2297951