I've been trying for a while to set up a two-way binding on a Spinner.
There are many example of this on the web and here on stack overflow but none of them works for me.
It's just a country spinner, I've defined a country adapter for it with this methods:
@InverseBindingAdapter(attribute = "selectedCountry", event = "selectedCountryAttrChanged")
public static String bindCountryInverseAdapter(AppCompatSpinner pAppCompatSpinner) {
Object selectedItem = pAppCompatSpinner.getSelectedItem();
SpinnerAdapter adapter = pAppCompatSpinner.getAdapter();
if (adapter instanceof CountrySpinnerAdapter) {
return (String) selectedItem;
}
throw new UnsupportedOperationException("The adapter must be a CountrySpinnerAdapter");
}
@BindingAdapter(value = "selectedCountryAttrChanged", requireAll = false)
public static void bindCountryChanged(AppCompatSpinner pAppCompatSpinner, final InverseBindingListener newTextAttrChanged) {
AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
newTextAttrChanged.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
newTextAttrChanged.onChange();
}
};
pAppCompatSpinner.setOnItemSelectedListener(listener);
}
@BindingAdapter("selectedCountry")
public static void bindCountryValue(AppCompatSpinner pAppCompatSpinner, String newSelectedValue) {
SpinnerAdapter adapter = pAppCompatSpinner.getAdapter();
if (adapter instanceof CountrySpinnerAdapter) {
((CountrySpinnerAdapter) adapter).bindSelectedValue(pAppCompatSpinner, newSelectedValue);
return;
}
throw new UnsupportedOperationException("The adapter must be a CountrySpinnerAdapter");
}
the bindCountryChanged
method is never called.
I've also tried this variant (following other examples):
@BindingAdapter(value = {"selectedCountry", "selectedCountryAttrChanged"}, requireAll = false)
public static void bindCountryValueChanged(AppCompatSpinner pAppCompatSpinner, String newSelectedValue, final InverseBindingListener newTextAttrChanged) {
AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
newTextAttrChanged.onChange();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
newTextAttrChanged.onChange();
}
};
pAppCompatSpinner.setOnItemSelectedListener(listener);
}
This is called but newTextAttrChanged
is always null.
The layout, binding part:
<data>
<variable
name="customer"
type="my.package.CustomerBinding" />
</data>
And the widget:
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/editCountry"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:spinnerMode="dropdown"
app:adapter="@{customer.countrySpinnerAdapter}"
app:selectedCountry="@{customer.country}" />
country
id just an ObservableField<String>
and countrySpinnerAdapter
is a BaseAdapter
for the list of countries.
Android gradle plugin:
classpath 'com.android.tools.build:gradle:2.2.1'
Tools versions:
buildToolsVersion "24.0.2"
And of course data binding is enabled:
dataBinding {
enabled = true
}
Why newTextAttrChanged
is always null / the BindingAdapter is never calld? What am I doing wrong?
You are missing the =
in the binding expression to notify the system that you would like to use this binding as a two-way binding.
app:selectedCountry="@{customer.country}"
should be
app:selectedCountry="@={customer.country}"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With