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

问题描述 投票:20回答:5

我正在使用新的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; }
    }
java android android-layout android-databinding
5个回答
26
投票

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

1.'@ ='用于双向数据绑定

2.双向自定义数据绑定需要“BindingAdapter”和“InverseBindingAdapter”注释来实现这一点。

对于第一项,许多博客显示“@ =”用于双向数据绑定。 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可以使用“BindingAdapter”和“InverseBindingAdapter”注释双向绑定。

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

首先,创建ViewModel或使用Pojo

视图模型

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

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

}

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

event的默认值是以“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>

运行代码时,它将显示“星期三”作为微调器的默认值。希望这可以为许多人提供帮助


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

6
投票

1线解决方案

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

而已!无需自定义BindingAdapter。

Spinner已经支持属性selectionselectedItemPosition的双向绑定。见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}"
    >

main activity.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 ObservableFieldLive Data。它是由你决定。我使用BaseObservable因为它非常简单。只需从BaseObservable扩展,所有字段现在都可以观察到。


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

0
投票

请参阅my answer,以实现与微调器最简单的数据绑定。确实,我们需要一个适配器来完成更多任务。

那里有XML代码。

Java的:


    //  Data binding
        ActivityParentsRegBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_parents_reg);
        binding.setCities(ConstData.getCitiesList());
© www.soinside.com 2019 - 2024. All rights reserved.