我正在使用新的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; }
}
答案 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)
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) {
}
});