Подтвердить что ты не робот

Android spinner Data Binding с использованием XML и отображает выбранные значения

Я использую новую привязку данных к андроиду, и она отлично работает. Я могу выполнить привязку данных, используя EditText, TextView, Radio и checkbox. Теперь я не могу выполнить привязку данных в spinner.

Найден какой-то ключ в следующей ссылке: привязка данных spinner для Android с помощью XML-макета

Но, все еще не в состоянии найти решение. Также необходимо выполнить двухстороннюю привязку данных. Должно отразить выбранное значение данных счетчика.

Может кто-нибудь, пожалуйста, покажет мне пример?

Вот мой код 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>

Просмотр модели:

 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; }
    }
4b9b3361

Ответ 1

Я обнаружил, что кое-что может быть полезным, но этого нет в официальной документации по двустороннему связыванию данных.

1. Использование "@=" для двусторонней привязки данных

2. Для достижения этой цели необходима двусторонняя привязка пользовательских данных "BindingAdapter" и "InverseBindingAdapter".

Для первого элемента многие блоггеры показали использование "@=" для двухстороннего связывания данных. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/

Для второго элемента, как ответил здесь @George Mound (курсор редактирования текста сбрасывается влево, когда текст по умолчанию для edittext представляет собой значение с плавающей точкой), EditText можно связать в двух направлениях, используя аннотации "BindingAdapter" и "InverseBindingAdapter".

Следуя инструкциям, вы можете создать двухсторонний метод привязки для прядильщика.

Во-первых, создайте вашу ViewModel или используйте 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;
    }
}

Во-вторых, добавьте его в свой XML.

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

В-третьих, добавьте привязку Util

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

}

Как вы видели, он использовал selectedValue в качестве переменной для выбранного по умолчанию значения, но что такое selectedValueAttrChanged?? Я думал, что это сложно (я не знаю, почему это не нуль, когда он вызывается), его не нужно добавлять в XML, так как это только обратный вызов для прослушивания элемента, измененного в счетчике. А затем вы устанавливаете onItemSelectedListener и настраиваете его на вызов функции InverseBindingListener onchange() (документация и пример здесь: https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html) Событием по умолчанию будет "android: textAttrChanged ", и если вы хотите иметь обратную двустороннюю привязку, вам нужно использовать атрибут с суффиксом" AttrChanged "

Значением по умолчанию для события является имя атрибута с суффиксом "AttrChanged". В приведенном выше примере значением по умолчанию было бы android: textAttrChanged, даже если оно не было предоставлено.

Наконец, в вашей деятельности и вашем 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>

Когда вы запускаете код, он будет показывать "Среда" в качестве значения по умолчанию для счетчика. Надеюсь, что это может помочь многим людям

Ответ 2

Вы можете сделать это простым способом с помощью onItemSelected и получить выбранную позицию и текст выбранного элемента.

1) добавьте атрибут onItemSelected к вашему счетчику, как показано ниже:

<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) теперь вам нужно добавить этот метод в вашу 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...
}

В массиве может быть что-то вроде этого, которое необходимо сохранить в 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>

Когда макет нарисован, вызывается onItemSelected, тогда вы можете установить начальное значение:

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

Ответ 3

1 линия Решение

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

Это! Не нужно делать пользовательские BindingAdapter.

Spinner уже поддерживает двустороннюю привязку путем selection атрибутов и selectedItemPosition. Смотрите документацию по Android

Вам просто нужно использовать двухстороннее связывание selectedItemPosition чтобы изменения в счетчике отражались на поле вашей модели.

пример

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()]);
    }
}

Если вам нужно получить выбранный элемент из вашего кода в любое время, используйте

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

Сделайте вашу переменную @Bindable, если вам нужно программно изменить ее.

binding.getItem().setSelectedItemPosition(4);

В противном случае вы можете удалить @Bindable и notifyPropertyChanged(BR.selectedItemPosition); ,

Вы можете использовать любой из BaseObservable или ObservableField или Live Data. Это тебе решать. Я использую BaseObservable, потому что это очень просто. , просто продолжайте из BaseObservable, и все поля теперь доступны для наблюдения.

Ответ 4

@Long Ranger Мне очень нравится ваш ответ, но я думаю, что нам нужно кое-что сделать, чтобы разорвать петлю. Вот так:

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

Ответ 5

Смотрите мой ответ, чтобы добиться простейшего связывания данных с помощью счетчика. На самом деле нам нужен адаптер для выполнения дальнейших задач.

XML-код есть.

Джава:


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

Ответ 6

1-Создайте один class для имени местоположения и установите свой код для класса, например

public class Location {

    private int Id;
    private String Title;

    public Location(int Id,String Title){
        this.Id=Id;
        this.Title=Title;
    }

    public int getId() {
        return Id;
    }

    public void setId(int id) {
        Id = id;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        Title = title;
    }

    @Override
    public String toString() {
        return Title;
    }
}

2-Создайте один Spinner и напишите этот код на Java

Spinner cmb_Area = view.findViewById(R.id.Fragment_Add_Home_cmb_Area);

ArrayList<Location> locations= new ArrayList<>();

locations.add(new Location(1,"London"));
locations.add(new Location(2,"Paris"));

ArrayAdapter<Location> adapter2 = new ArrayAdapter<Location>(getActivity(), android.R.layout.simple_spinner_dropdown_item, locations);

cmb_Area.setAdapter(adapter2);

3-Написать этот код для выбора элемента

cmb_Area.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        Location location = (Location) parent.getSelectedItem();
        Toast.makeText(getActivity(),location.getId(),Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
    }
});