如何让数据绑定表达式对同一布局中 EditText 的更改做出反应?
How Can I Have a Data Binding Expression React To Changes In an EditText In the Same Layout?
假设我有一个 ID 为 foo
的 EditText
。在同一布局资源的其他地方,我有一个 Button
,我只想在 EditText
.
中有文本时启用 Button
我认为这行得通:
<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}" />
生成的绑定 class 确实根据 foo
中文本的长度在 bar
上调用了 setEnabled()
... 但仅当 executeBindings()
叫做。这似乎不会在用户键入时被调用,因此我的 Button
的启用状态不会根据用户在 EditText
.
中输入文本而改变
我可以解决这个问题,但感觉应该可行。有什么我想念的吗?这是已知的限制吗?
更新
只需将 foo.text.length
更改为 foo.text.length()
。
旧解决方案
有些要点,也许你错过了。
1。使用 BaseObservable
如果你的 model
extends
BaseObservable
那么你需要 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);
}
}
原因 是,当您使用 text.length
时,您需要在更改时调用所有依赖元素。因为 text.length
是不可观察的,所以你需要手动调用它。生成的绑定 class 调用 setName(value)
但它不会更改 text.length
依赖视图。
2。使用 MutableLiveData
如果您使用 MutableLiveData
则必须提供 LifeCycleOwner
binding.setLifecycleOwner(this);
3。使用 ObservableField
(最短方法)
另一种简单的方法是将 ObservableField
用于 foo.text
我说简单因为在这种情况下你不需要制作这个字段Bindable
。
public class UserObservableField {
private ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
}
我用其中的 3 个解决方案创建了一个示例,所有解决方案都有效!
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;
}
}
}
我把所有模型都放在里面 Activity。我尽量解释清楚了,还有不明白的地方可以评论
输出
我想我还可以在这里添加一些东西,我个人不喜欢公开可变的实时数据。因此,您可以使用 android:afterTextChanged
属性并执行类似 android:afterTextChanged="@{(text) -> viewmodel.onSomethingChanged(text)}"
的操作。这样你就不会公开你的 MutableLiveData 对象。
假设我有一个 ID 为 foo
的 EditText
。在同一布局资源的其他地方,我有一个 Button
,我只想在 EditText
.
Button
我认为这行得通:
<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}" />
生成的绑定 class 确实根据 foo
中文本的长度在 bar
上调用了 setEnabled()
... 但仅当 executeBindings()
叫做。这似乎不会在用户键入时被调用,因此我的 Button
的启用状态不会根据用户在 EditText
.
我可以解决这个问题,但感觉应该可行。有什么我想念的吗?这是已知的限制吗?
更新
只需将 foo.text.length
更改为 foo.text.length()
。
旧解决方案
有些要点,也许你错过了。
1。使用 BaseObservable
如果你的 model
extends
BaseObservable
那么你需要 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);
}
}
原因 是,当您使用 text.length
时,您需要在更改时调用所有依赖元素。因为 text.length
是不可观察的,所以你需要手动调用它。生成的绑定 class 调用 setName(value)
但它不会更改 text.length
依赖视图。
2。使用 MutableLiveData
如果您使用 MutableLiveData
则必须提供 LifeCycleOwner
binding.setLifecycleOwner(this);
3。使用 ObservableField
(最短方法)
另一种简单的方法是将 ObservableField
用于 foo.text
我说简单因为在这种情况下你不需要制作这个字段Bindable
。
public class UserObservableField {
private ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
}
我用其中的 3 个解决方案创建了一个示例,所有解决方案都有效!
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;
}
}
}
我把所有模型都放在里面 Activity。我尽量解释清楚了,还有不明白的地方可以评论
输出
我想我还可以在这里添加一些东西,我个人不喜欢公开可变的实时数据。因此,您可以使用 android:afterTextChanged
属性并执行类似 android:afterTextChanged="@{(text) -> viewmodel.onSomethingChanged(text)}"
的操作。这样你就不会公开你的 MutableLiveData 对象。