Reputation: 5371
I have Spinner
and some count of EditText
at layout. I want to bind type of EditText
to state of Spinner
. I.e.
Spinner
input type of all EditText
components must be changed to floating point numbersTo achive this I define binding adapter below:
@BindingAdapter(value = {"bind:selectedValueAttrChanged", "bind:relatedInputs"}, requireAll = false)
public static void setMeasurementUnit(final Spinner spinner, final InverseBindingListener listener, final AppCompatEditText... relatedInputs){
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
listener.onChange();
String selectedUnit = (String) spinner.getSelectedItem();
for (EditText editText : relatedInputs) {
if (editText == null) continue;
if (selectedUnit.equals("INTEGER"))
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
else if(selectedUnit.equals("FLOAT"))
editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
listener.onChange();
}
});
}
And bind EditText
to Spinner
at layout file:
<LinearLayout>
<android.support.v7.widget.AppCompatEditText
android:id="@+id/edit_text_1"/>
<android.support.v7.widget.AppCompatSpinner
bind:relatedInputs="@{editText1}"/>
</LinearLayout>
It's produce the error at compile time:
data binding error ****msg:Cannot find the setter for attribute 'bind:relatedInputs' with parameter type android.support.v7.widget.AppCompatEditText on android.support.v7.widget.AppCompatSpinner.
When I tried declare and pass array of EditText
<android.support.v7.widget.AppCompatSpinner
bind:relatedInputs="@{new AppCompatEditText[]{editText1, editText2}}"/>
I'm got syntax error:
data binding error ****msg:Syntax error: extraneous input 'AppCompatEditText' expecting {<EOF>, ',', '.', '::', '[', '+', '-', '*', '/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof', '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}
or
P.S. this example very simplified and can contain logical errors, but it fully explain, what I want to achive.
Upvotes: 2
Views: 2241
Reputation: 20926
Android Data Binding doesn't let you pass in varargs. You may have only have one value for each attribute. You may pass lists or arrays as attribute values, but you can't create them on the fly (new
is not allowed in the expression language).
It is better to invert the problem and assign the android:inputType
attribute to an expression based on the selected item.
<LinearLayout>
<android.support.v7.widget.AppCompatEditText
android:inputType="@{Converters.getInputType(spinner1.selectedItem)}"/>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/spinner1"/>
</LinearLayout>
You'll need the Converters class also:
public class Converters {
public static int getInputType(Object obj) {
if (!(obj instanceof String)) {
return InputType.TYPE_CLASS_TEXT; // Don't know what to do
}
String selectedUnit = (String) obj;
if (selectedUnit.equals("INTEGER")) {
return InputType.TYPE_CLASS_NUMBER;
} else if(selectedUnit.equals("FLOAT")) {
return InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
}
return InputType.TYPE_CLASS_TEXT; // Don't know what to do
}
}
Upvotes: 1
Reputation: 5517
Another approach would be:
//create a Observable for the input type:
public final ObservableInt decOrInt = new ObservableInt(InputType.TYPE_NUMBER_FLAG_DECIMAL);
Add a listener to your spinner:
binding.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
decOrInt.set(i != 0 ?
InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL :
InputType.TYPE_CLASS_NUMBER);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
decOrInt.set(InputType.TYPE_CLASS_NUMBER);
}
});
And in your xml, for every EditText
you want:
<!-- act would be the class where you store your decOrInt-->
<EditText
android:id="@+id/edit_text"
android:inputType="@{act.decOrInt}" />
A decimal input corresponds to InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL
, an integer input corresponds to InputType.TYPE_CLASS_NUMBER
.
It is possible to enter a float and change the selection to int - you'll need to add an error or something to prevent this.
Upvotes: 0