2016-06-17 11 views
12

Sto utilizzando il nuovo binding di dati Android e funziona benissimo. Sono in grado di eseguire il binding dei dati utilizzando EditText, TextView, Radio e la casella di controllo. Ora, non sono in grado di eseguire il databinding in spinner.Spinner Android Data Binding tramite XML e mostra i valori selezionati

trovato qualche indizio in link qui sotto: Android spinner data binding with xml layout

Ma, ancora in grado di trovare la soluzione. Inoltre, è necessario eseguire il databinding bidirezionale. Dovrebbe riflettere il valore selezionato dei dati dello spinner.

Qualcuno può mostrarmi un esempio?

Ecco il mio codice 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> 

Vista Modello:

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

risposta

14

ho trovato quarantina potrebbe essere utile, ma non è nella documentazione ufficiale per i dati a due vie vincolanti.

1. '@ =' utilizzo per i dati a due vie vincolante

2. I dati a due vie personalizzati vincolanti esigenze "BindingAdapter" e "InverseBindingAdapter" annotazione per raggiungere questo obiettivo.

Per il primo articolo, un sacco di blogger ha mostrato l'uso di "@ =" per il bind dei dati bidirezionale. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/

Per il secondo punto, come @George Mound risposto qui (Edit text cursor resets to left when default text of edittext is a float value) l'EditText può essere legano a due vie con "BindingAdapter" e annotazione "InverseBindingAdapter".

Seguendo le istruzioni, è possibile creare il metodo di rilegatura a due vie per lo spinner.

In primo luogo, crea il tuo ViewModel o utilizzare 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; 
    } 
} 

In secondo luogo, aggiungere nella tua xml.

<android.support.v7.widget.AppCompatSpinner 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:entries="@array/days" 
      bind:selectedValue="@={viewModel.text}"/> 

In terzo luogo, aggiungere il 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(); 
    } 

} 

come la sega, ha usato "SelectedValue", come variabile per il valore di default selezionato, ma ciò che è "selectedValueAttrChanged" ?? Ho pensato che questo sia complicato (non so perché non sia nullo quando viene chiamato), non è necessario aggiungerlo nell'xml poiché è solo il callback per l'ascolto dell'elemento modificato nella casella di selezione.E quindi si imposta onItemSelectedListener e si imposta la chiamata alla funzione InverseBindingListener onchange() (Documentazione ed esempio: https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html) L'evento predefinito sarà "android: textAttrChanged" e se si desidera disporre di inversbind bind a due vie personalizzato, è necessario utilizzare l'attributo con il suffisso "AttrChanged"

il valore predefinito per l'evento è il nome dell'attributo suffisso "AttrChanged". Nell'esempio sopra, il valore predefinito sarebbe stato android: textAttrChanged anche se non è stato fornito.

Infine, nella vostra attività e la vostra 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> 

Quando si esegue il codice, mostrerà "Mercoledì" come valore di default per lo spinner. Spero che questo può aiutare per molte persone

+2

ricevo un NullPointerException da questo , newTextAttrChanged è nullo anche se hai detto che non è –

+0

^^ probabilmente ti manca "=" dopo "@" nel tuo xml. Dovrebbe apparire come 'bind: selectedValue =" @ = {viewModel.text} "' –

0

@Long Ranger mi piace molto la tua risposta, ma penso che ci sia qualcosa che dobbiamo fare per rompere il loop.like questo:

@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.equlas(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); 
    } 
} 
Problemi correlati