Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am using the new android data binding and it works great. I am able to perform data binding using EditText, TextView, Radio and checkbox. Now, I am not able to do the databinding in spinner.

Found some clue in below link: Android spinner data binding with xml layout

But, still not able to find the solution. Also need to perform the two way databinding. Should reflect the spinner data selected value.

Can someone please show me with an example?

Here is my xml code:

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

View Model:

 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; }
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
363 views
Welcome To Ask or Share your Answers For Others

1 Answer

I found somethings might be helpful but it is not in the official documentation for the two-way data binding.

1. '@=' usage for the two-way data binding

2. Two-way custom data binding needs "BindingAdapter" and "InverseBindingAdapter" annotation to achieve this.

For the first item, lots of blogger showed the usage of "@=" for two way data binding. https://halfthought.wordpress.com/2016/03/23/2-way-data-binding-on-android/

For the second item, as @George Mound replied here (Edit text cursor resets to left when default text of edittext is a float value) the EditText can be bind in two-way using "BindingAdapter" and "InverseBindingAdapter" annotation.

Following the instructions, you can build up your two-way binding method for spinner.

Firstly, create your ViewModel or use 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;
    }
}

Secondly, add it into your xml.

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

Thirdly, add your 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();
    }

}

As your saw, it used "selectedValue" as variable for the default selected value, but what is "selectedValueAttrChanged" ?? I thought this one is tricky (I don't know, why it is not null when it is called) , it is not need to be added in the xml since it is only the callback for listening the item changed in the spinner. And then you set the onItemSelectedListener and set it to call InverseBindingListener onchange() function (Documentation and example here : https://developer.android.com/reference/android/databinding/InverseBindingAdapter.html) The default event will be "android:textAttrChanged" and if you want to have custom two-way bind inversebind, you need to use the attribute with suffix "AttrChanged"

The default value for event is the attribute name suffixed with "AttrChanged". In the above example, the default value would have been android:textAttrChanged even if it wasn't provided.

Finally, in your activity and your 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>

When you run the code, it will show "Wednesday" as the default value for the spinner.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...