java - ejemplo - Enlace de datos de Android spinner usando XML y muestra los valores seleccionados
databinding expression android (5)
Estoy usando el nuevo enlace de datos de Android y funciona muy bien. Puedo realizar el enlace de datos utilizando EditText, TextView, Radio y la casilla de verificación. Ahora, no puedo hacer el enlace de datos en spinner.
Encontró alguna pista en el siguiente enlace: Enlace de datos de Android con diseño xml
Pero, todavía no es capaz de encontrar la solución. También es necesario realizar el enlace de datos de dos vías. Debe reflejar el valor seleccionado de los datos del spinner.
¿Puede alguien mostrarme un ejemplo?
Aquí está mi código 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>
Ver Modelo:
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; }
}
1 solución de línea
android:selectedItemPosition="@={item.selectedItemPosition}"
¡Eso es! No hay necesidad de hacer BindingAdapter personalizado.
Spinner ya admite el enlace bidireccional mediante la
selection
atributos yselectedItemPosition
. Ver la documentación de AndroidSolo tiene que usar el enlace de dos vías
selectedItemPosition
para que el cambio en el giro se refleje en el campo de su modelo.
Ejemplo
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()]);
}
}
Si necesita obtener un elemento seleccionado de su código en cualquier momento, use este
binding.getItem().getSelectedItemPosition(); // get selected position
getResources().getStringArray(R.array.items)[binding.getItem().getSelectedItemPosition()]) // get selected item
Haga su variable @Bindable si necesita cambiarla programáticamente.
binding.getItem().setSelectedItemPosition(4);
De lo contrario, puede eliminar @Bindable y notifyPropertyChanged(BR.selectedItemPosition);
.
Puedes usar cualquiera de BaseObservable o ObservableField o Live Data . Es tu decision. Yo uso BaseObservable porque es muy simple. , solo extienda desde BaseObservable y todos los campos son observables ahora.
@Long Ranger. Realmente me gusta tu respuesta, pero creo que hay algo que debemos hacer para romper el bucle. Así:
@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);
}
}
Descubrí que algunas cosas podrían ser útiles, pero no está en la documentación oficial para el enlace de datos bidireccional.
1. ''@ ='' uso para el enlace de datos de dos vías
2. El enlace de datos personalizado bidireccional necesita la anotación "BindingAdapter" y "InverseBindingAdapter" para lograr esto.
Para el primer artículo, muchos bloggers mostraron el uso de "@ =" para el enlace de datos bidireccional. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/
Para el segundo elemento, como @George Mound respondió aquí (el cursor del texto de edición se restablece a la izquierda cuando el texto predeterminado del texto de edición es un valor flotante ), el EditText se puede vincular de dos maneras usando la anotación "BindingAdapter" y "InverseBindingAdapter".
Siguiendo las instrucciones, puedes construir tu método de enlace bidireccional para el hilandero.
En primer lugar, crea tu ViewModel o usa 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;
}
}
En segundo lugar, agrégalo a tu xml.
<android.support.v7.widget.AppCompatSpinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:entries="@array/days"
bind:selectedValue="@={viewModel.text}"/>
En tercer lugar, agregue su enlaceUtil
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();
}
}
Como lo vio, utilizó "selectedValue" como variable para el valor seleccionado predeterminado, pero ¿qué es "selectedValueAttrChanged"? Pensé que esto es complicado (no sé por qué no es nulo cuando se llama), no es necesario agregarlo en el xml, ya que es solo la devolución de llamada para escuchar el elemento cambiado en el control numérico. Y luego configuras onItemSelectedListener y lo configuras para llamar a la función onchange () de InverseBindingListener (Documentación y ejemplo aquí: https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html ) El evento predeterminado será "android: textAttrChanged "y si desea tener un enlace inverso de enlace bidireccional personalizado, debe usar el atributo con el sufijo" AttrChanged "
El valor predeterminado para el evento es el nombre del atributo con el sufijo "AttrChanged". En el ejemplo anterior, el valor predeterminado habría sido android: textAttrChanged incluso si no se hubiera proporcionado.
Finalmente, en tu actividad y tu 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>
Cuando ejecute el código, se mostrará "Miércoles" como el valor predeterminado para la ruleta. Espero que esto pueda ayudar a muchas personas.
Puede hacerlo de forma simple con el uso de un elemento seleccionado y obtener la posición seleccionada y el texto del elemento seleccionado.
1) agregue el atributo onItemSelected a su hilandero como se muestra a continuación:
<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) ahora necesita agregar este método a su 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...
}
La matriz podría ser algo como esto que debe guardar en los valores / 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>
Cuando se dibuja el diseño, se invoca onItemSelected , luego puede establecer el valor inicial:
parent.setSelection(1); //1 is position of initializing value
Ver mi respuesta allí para lograr el enlace de datos más simple con el spinner. De hecho, necesitamos un adaptador para hacer más tareas.
El código XML está ahí.
Java:
// Data binding
ActivityParentsRegBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_parents_reg);
binding.setCities(ConstData.getCitiesList());