Suppose that I have an EditText with an ID of foo. Elsewhere in the same layout resource, I have a Button, and I want to enable the Button only if there is text in the EditText.
I thought that this would work:
<Button
android:id="@+id/bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{listener}"
android:text="Um, hi!"
android:enabled="@{foo.text.length > 0}" />
The generated binding class does indeed call setEnabled() on bar based on the length of the text in foo... but only when executeBindings() is called. That does not seem to be called as the user types, so the enabled state of my Button does not change based on the user entering text in the EditText.
I can work around this, but it feels like this should be working. Is there something that I'm missing? Is this a known limitation?
Just change foo.text.length to foo.text.length().
Some points, perhaps which you missed.
BaseObservable
If your model extends BaseObservable then you need to make food.text @Bindable.
public class UserBaseObservable extends BaseObservable {
private String name;
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
Reason being, when you use text.length then you need to invoke all dependent elements when it is changed. Because text.length is not observable, so you need to manually invoke it. Generated binding class calls setName(value) but it does not change text.length dependent views.
MutableLiveData
If you use MutableLiveData then it is nessesary to provide LifeCycleOwner
binding.setLifecycleOwner(this);
ObservableField (Shortest approach)Another easy approach is to use ObservableField for foo.text
I said easy because you don't need to make this field Bindable in this case.
public class UserObservableField {
private ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
}
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
>
<data>
<variable
name="userObservableField"
type="com.innovanathinklabs.sample.activities.LoginActivity.UserObservableField"/>
<variable
name="userMutable"
type="com.innovanathinklabs.sample.activities.LoginActivity.UserMutable"/>
<variable
name="userBaseObservable"
type="com.innovanathinklabs.sample.activities.LoginActivity.UserBaseObservable"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:text="@={userObservableField.name}"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="@{userObservableField.name.length()>0}"
android:text="Proceed"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:text="@={userMutable.name}"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="@{userMutable.name.length()>0}"
android:text="Proceed"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="Enter your name"
android:text="@={userBaseObservable.name}"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="@{userBaseObservable.name.length()>0}"
android:text="Proceed"/>
</LinearLayout>
</layout>
LoginActivity.java
public class LoginActivity extends AppCompatActivity {
ActivityLoginBinding binding;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
binding.setLifecycleOwner(this); // necessary for LiveData to work
binding.setUserObservableField(new UserObservableField());
binding.setUserBaseObservable(new UserBaseObservable());
binding.setUserMutable(new UserMutable());
}
public static class UserObservableField {
private ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
}
public static class UserBaseObservable extends BaseObservable {
private String name;
// necessary for updating button
@Bindable
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
}
public static class UserMutable {
private MutableLiveData<String> name = new MutableLiveData<>();
public MutableLiveData<String> getName() {
return name;
}
public void setName(MutableLiveData<String> name) {
this.name = name;
}
}
}
I placed all models inside Activity. I tried to explain well, still you can make comment if you have any confusion.

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