studio ejemplo databindingutil databinding data compiler java android android-layout android-databinding

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 y selectedItemPosition . Ver la documentación de Android

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