Java 使用 XML 的 Android spinner 数据绑定并显示选定的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37874091/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android spinner Data Binding using XML and show the selected values
提问by San Jaisy
I am using the new android data binding and it works great. I am able to perform data binding using EditText, TextView, Radio and checkbox. Now, I am not able to do the databinding in spinner.
我正在使用新的 android 数据绑定,效果很好。我能够使用 EditText、TextView、Radio 和复选框执行数据绑定。现在,我无法在微调器中进行数据绑定。
Found some clue in below link: Android spinner data binding with xml layout
在下面的链接中找到了一些线索: Android spinner data binding with xml layout
But, still not able to find the solution. Also need to perform the two way databinding. Should reflect the spinner data selected value.
但是,仍然无法找到解决方案。还需要执行双向数据绑定。应反映微调数据选定值。
Can someone please show me with an example?
有人可以给我举个例子吗?
Here is my xml
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>
View Model:
查看型号:
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; }
}
回答by Long Ranger
I found somethings might be helpful but it is not in the official documentation for the two-way data binding.
我发现有些东西可能会有所帮助,但它不在双向数据绑定的官方文档中。
1. '@=' usage for the two-way data binding
1. '@=' 双向数据绑定的用法
2. Two-way custom data binding needs "BindingAdapter" and "InverseBindingAdapter" annotation to achieve this.
2、双向自定义数据绑定需要“BindingAdapter”和“InverseBindingAdapter”注解来实现。
For the first item, lots of blogger showed the usage of "@=" for two way data binding. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/
对于第一项,很多博主展示了“@=”用于双向数据绑定的用法。https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/
For the second item, as @George Mound replied here (Edit text cursor resets to left when default text of edittext is a float value) the EditText can be bind in two-way using "BindingAdapter" and "InverseBindingAdapter" annotation.
对于第二项,正如@George Mound 在这里回答的那样(当 edittext 的默认文本为浮点值时,编辑文本光标重置为左侧)可以使用“BindingAdapter”和“InverseBindingAdapter”注释以双向方式绑定 EditText。
Following the instructions, you can build up your two-way binding method for spinner.
按照说明,您可以建立微调器的双向绑定方法。
Firstly, create your ViewModel or use Pojo
首先,创建您的 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;
}
}
Secondly, add it into your xml.
其次,将其添加到您的 xml 中。
<android.support.v7.widget.AppCompatSpinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/days"
bind:selectedValue="@={viewModel.text}"/>
Thirdly, add your bindingUtil
第三,添加您的 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();
}
}
As your saw, it used "selectedValue" as variable for the default selected value, but what is "selectedValueAttrChanged" ?? I thought this one is tricky(I dunno why it is not null when it is called) , it is not need to be added in the xmlsince it is only the callback for listening the item changed in the spinner. And then you set the onItemSelectedListener and set it to call InverseBindingListener onchange()function (Documentation and example here : https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html) The default event will be "android:textAttrChanged" and if you want to have custom two-way bind inversebind, you need to use the attribute with suffix "AttrChanged"
如您所见,它使用“selectedValue”作为默认选定值的变量,但什么是“selectedValueAttrChanged”?我认为这个很棘手(我不知道为什么它在调用时不为空),不需要在 xml 中添加它,因为它只是用于侦听微调器中更改的项目的回调。然后设置 onItemSelectedListener 并将其设置为调用 InverseBindingListener onchange()函数(此处的文档和示例:https: //developer.android.com/reference/android/databinding/InverseBindingAdapter.html)默认事件将为“android: textAttrChanged”,如果要自定义双向绑定反向绑定,则需要使用后缀为“AttrChanged”的属性
The default value for event is the attribute name suffixed with "AttrChanged". In the above example, the default value would have been android:textAttrChanged even if it wasn't provided.
event 的默认值是带有“AttrChanged”后缀的属性名称。在上面的示例中,即使未提供,默认值也会是 android:textAttrChanged。
Finally, in your activity and your string.xml
最后,在您的活动和您的 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
字符串.xml
<array name="days">
<item name="Mon">Monday</item>
<item name="Tue">Tuesday</item>
<item name="Wed">Wednesday</item>
</array>
When you run the code, it will show "Wednesday" as the default value for the spinner. Hope this can help for many people
当您运行代码时,它将显示“星期三”作为微调器的默认值。希望这可以帮助很多人
回答by lulalagulu
@Long Ranger I really like your answer, but i think there is something we need to do to break the loop.like this:
@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);
}
}
回答by Mohsen Beiranvand
You can do it simple way with use onItemSelected and get selected position and selected item text.
您可以使用 onItemSelected 以简单的方式完成并获取选定的位置和选定的项目文本。
1) add onItemSelectedattribute to your spinner like below:
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) now you need to add this method to your viewModel:
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...
}
array could be somethings like this must save to values/item_list.xml:
数组可能是这样的,必须保存到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>
When the layout is drawn, onItemSelectedis invoked , then you can set initial value:
绘制布局时,调用onItemSelected,然后您可以设置初始值:
parent.setSelection(1); //1 is position of initializing value
回答by Khemraj
1 Line Solution
1 条线路解决方案
android:selectedItemPosition="@={item.selectedItemPosition}"
android:selectedItemPosition="@={item.selectedItemPosition}"
That's it!No need to make custom BindingAdapter.
就是这样!无需制作自定义 BindingAdapter。
Spinner already supports two-way binding by attributes
selection
andselectedItemPosition
. See Android DocumentationYou just need to use two way binding
selectedItemPosition
so that change on spinner reflect on your model field.
Spinner 已经支持通过属性
selection
和 进行双向绑定selectedItemPosition
。请参阅Android 文档您只需要使用两种方式绑定,
selectedItemPosition
以便微调器上的更改反映在您的模型字段上。
Example
例子
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
活动_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
主活动.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()]);
}
}
If you need to get selected item from your code any time, then use this
如果您需要随时从代码中获取所选项目,请使用此
binding.getItem().getSelectedItemPosition(); // get selected position
getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]) // get selected item
Make your variable @Bindableif you need to programmatically change it.
如果您需要以编程方式更改它,请使用您的变量@Bindable。
binding.getItem().setSelectedItemPosition(4);
Otherwise you can remove @Bindableand notifyPropertyChanged(BR.selectedItemPosition);
.
否则,您可以删除@Bindable和notifyPropertyChanged(BR.selectedItemPosition);
.
You can use any of BaseObservableor ObservableFieldor Live Data. It is up to you. I use BaseObservablebecause it is very simple., just extend from BaseObservable and all fields are observable now.
您可以使用BaseObservable或ObservableField或Live Data 中的任何一个。它是由你决定。我使用BaseObservable因为它非常简单。, 只是从 BaseObservable 扩展,现在所有字段都是可观察的。
回答by ForWebTech
See my answerthere to achieve simplest data binding with spinner. Indeed we need an Adapter to do further tasks.
请参阅我的答案,以使用微调器实现最简单的数据绑定。事实上,我们需要一个适配器来做进一步的任务。
XML code is there.
XML 代码在那里。
Java:
爪哇:
// Data binding
ActivityParentsRegBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_parents_reg);
binding.setCities(ConstData.getCitiesList());
回答by Feroz Khan
For me, https://stackoverflow.com/a/50338894/6791222this solution worked perfectly.
As mentioned in the solution, you should bind android:selectedItemPosition
attribute.
You can just copy paste the following in your view model and see the magic work.
对我来说,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);
}
And in your xml just use android:selectedItemPosition="@={viewModel.value}"
在你的 xml 中只需使用android:selectedItemPosition="@={viewModel.value}"