使用XML的Android微调器数据绑定并显示选定的值

时间:2016-06-17 05:54:27

标签: java android android-layout android-databinding

我正在使用新的Android数据绑定,效果很好。我可以使用EditText,TextView,Radio和复选框执行数据绑定。现在,我无法在微调器中进行数据绑定。

在以下链接中找到一些线索: Android spinner data binding with xml layout

但是,仍然无法找到解决方案。还需要执行双向数据绑定。应该反映微调器数据的选择值。

有人可以给我看一个例子吗?

这是我的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; }
    }

7 个答案:

答案 0 :(得分:26)

我发现某些内容可能会有所帮助,但它不在双向数据绑定的官方文档中。

<强> 1。 &#39; @ =&#39;用于双向数据绑定

<强> 2。双向自定义数据绑定需要&#34; BindingAdapter&#34;和&#34; InverseBindingAdapter&#34;实现此目的的注释。

对于第一项,很多博主都展示了&#34; @ =&#34;用于双向数据绑定。 https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/

对于第二项,正如@George Mound在这里回复(Edit text cursor resets to left when default text of edittext is a float value),EditText可以使用&#34; BindingAdapter&#34;双向绑定。和&#34; InverseBindingAdapter&#34;注解。

按照说明,您可以为微调器构建双向绑定方法。

首先,创建ViewModel或使用Pojo

视图模型

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}"/>

第三,添加你的bindingUtil

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

}

如你所见,它使用&#34; selectedValue&#34;作为默认选定值的变量,但是&#34; selectedValueAttrChanged&#34; ??我认为这个很棘手(我不知道为什么它在调用时不为空),它不需要在xml 中添加,因为它只是用于监听项目中的变量的回调微调。然后设置onItemSelectedListener并将其设置为调用InverseBindingListener onchange()函数(这里的文档和示例:https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html默认事件将是&#34; android:textAttrChanged& #34;如果你想要自定义双向绑定反向绑定,你需要使用带后缀的属性&#34; AttrChanged&#34;

  

event的默认值是后缀为的属性名称   &#34; AttrChanged&#34 ;.在上面的示例中,默认值为   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>

当您运行代码时,它将显示&#34; Wednesday&#34;作为微调器的默认值。希望这可以为很多人提供帮助

答案 1 :(得分:12)

您可以使用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

答案 2 :(得分:8)

1行解决方案

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

就是这样!!无需制作自定义的BindingAdapter。

  

Spinner已经支持通过属性selection和   selectedItemPosition。参见 Android Documentation

     

您只需要使用两种方式绑定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扩展而来,现在所有字段都是可观察的。

答案 3 :(得分:1)

对我来说,https://stackoverflow.com/a/50338894/6791222这个解决方案非常有效。 如解决方案中所述,您应该绑定android:selectedItemPosition属性。 您可以将以下内容复制粘贴到您的视图模型中,然后查看魔术作品。

@BindingAdapter("android:selectedItemPosition")
public static void setSelectedItemPosition(AdapterView view, int position) {
    if (view.getSelectedItemPosition() != position) {
        view.setSelection(position);
    }
}

@BindingAdapter(value = {"android:onItemSelected", "android:onNothingSelected",
        "android:selectedItemPositionAttrChanged" }, requireAll = false)
public static void setOnItemSelectedListener(AdapterView view, final OnItemSelected selected,
        final OnNothingSelected nothingSelected, final InverseBindingListener attrChanged)         
{
    if (selected == null && nothingSelected == null && attrChanged == null) {
        view.setOnItemSelectedListener(null);
    } else {
        view.setOnItemSelectedListener(
                new OnItemSelectedComponentListener(selected, nothingSelected, attrChanged));
    }
}

@BindingAdapter("android:selectedValueAttrChanged")
public static void setSelectedValueListener(AdapterView view,
        final InverseBindingListener attrChanged) {
    if (attrChanged == null) {
        view.setOnItemSelectedListener(null);
    } else {
        view.setOnItemSelectedListener(new OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                attrChanged.onChange();
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                attrChanged.onChange();
            }
        });
    }
}

@BindingAdapter("android:selectedValue")
public static void setSelectedValue(AdapterView<?> view, Object selectedValue) {
    Adapter adapter = view.getAdapter();
    if (adapter == null) {
        return;
    }
    // I haven't tried this, but maybe setting invalid position will
    // clear the selection?
    int position = AdapterView.INVALID_POSITION;

    for (int i = 0; i < adapter.getCount(); i++) {
        if (adapter.getItem(i) == selectedValue) {
            position = i;
            break;
        }
    }
    view.setSelection(position);
}

然后在您的xml中使用android:selectedItemPosition="@={viewModel.value}"

答案 4 :(得分:0)

@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 :(得分:0)

请参见my answer,以使用Spinner实现最简单的数据绑定。确实,我们需要一个适配器来执行更多任务。

有XML代码。

Java:


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

答案 6 :(得分:0)

例如,创建一个class来命名位置并将代码设置为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) {
    }
});