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