Android 如何让数据绑定表达式对同一布局中的EditText中的更改作出反应?
假设我有一个ID为Android 如何让数据绑定表达式对同一布局中的EditText中的更改作出反应?,android,android-databinding,Android,Android Databinding,假设我有一个ID为foo的EditText。在同一版面资源的其他地方,我有一个按钮,我只想在编辑文本中有文本时启用按钮 我认为这会起作用: <Button android:id="@+id/bar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@
foo
的EditText
。在同一版面资源的其他地方,我有一个按钮
,我只想在编辑文本
中有文本时启用按钮
我认为这会起作用:
<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}" />
生成的绑定类确实会根据foo
中的文本长度在bar
上调用setEnabled()。。。但仅当调用executeBindings()
时。这似乎不是作为用户类型调用的,因此my按钮的启用状态不会根据用户在EditText
中输入的文本而改变
我可以解决这个问题,但我觉得这应该是可行的。有什么我遗漏的吗?这是已知的限制吗?更新
只需将foo.text.length
更改为foo.text.length()
老办法
一些要点,也许你错过了
1.使用BaseObservable
如果您的型号
扩展了
基本可观察
,那么您需要制作食品.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
是不可观察的,所以您需要手动调用它。生成的绑定类调用setName(value)
,但它不会更改text.length
依赖视图
2.使用MutableLiveData
如果使用MutableLiveData
,则必须提供LifeCycleOwner
binding.setLifecycleOwner(this);
3.使用可观察字段
(最短路径)
另一种简单的方法是对foo.text
我说容易,因为在这种情况下,您不需要将此字段设置为可绑定的
public class UserObservableField {
private ObservableField<String> name = new ObservableField<>();
public ObservableField<String> getName() {
return name;
}
public void setName(ObservableField<String> name) {
this.name = name;
}
}
公共类userobserveField{
私有ObservableField name=新ObservableField();
公共observeField getName(){
返回名称;
}
公共void集合名(ObservableField名称){
this.name=名称;
}
}
我用其中的3个解决方案创建了一个示例,所有解决方案都有效!
activity\u 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;
}
}
}
公共类LoginActivity扩展了AppCompatActivity{
活动登录绑定;
@凌驾
创建时受保护的void(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
binding=DataBindingUtil.setContentView(这个,R.layout.activity\u登录名);
binding.setLifecycleOwner(this);//LiveData工作所必需的
binding.setUserObservableField(新的UserObservableField());
binding.setUserBaseObservable(新的UserBaseObservable());
binding.setUserMutable(newUserMutable());
}
公共静态类UserObservableField{
私有ObservableField name=新ObservableField();
公共observeField getName(){
返回名称;
}
公共void集合名(ObservableField名称){
this.name=名称;
}
}
公共静态类UserBaseObservable扩展了BaseObservable{
私有字符串名称;
//需要更新按钮
@装订的
公共字符串getName(){
返回名称;
}
公共void集合名(字符串名){
this.name=名称;
notifyPropertyChanged(BR.名称);
}
}
公共静态类UserMutable{
私有MutableLiveData name=新的MutableLiveData();
公共MutableLiveData getName(){
返回名称;
}
public void setName(MutableLiveData name){
this.name=名称;
}
}
}
我将所有模型都放在活动中。我试着解释得很好,但如果你有任何困惑,你仍然可以发表评论
输出
我想我也可以在这里添加一些东西,就我个人而言,我不喜欢公开可变的实时数据。因此,您可以使用android:posterextchanged
属性并执行类似于android:posterextchanged=“@{(text)->viewmodel.onSomethingChanged(text)}”的操作。这样你就不会暴露你的可变LiveData对象。如果你想让你的布局/视图对动态变化做出反应,你应该使用ObservableField
,Observable
或LiveData
字段:使用双向绑定在这样的变量中保存EditText
中的文本,然后你的按钮状态就会改变(如果您将按钮状态连接到这样的可观察字段
,这些都不能解决我的问题。Android的数据绑定允许绑定表达式引用同一布局中的其他小部件,并对这些小部件属性的更改作出反应。我正在询问这方面的特定场景(EditText
)在那里它没有像预期的那样工作。嗨,先生,我是你的超级粉丝:),我不明白您的问题。我认为您的解决方案不适用于更改按钮的启用状态。让我再次处理您的问题。数据绑定框架生成的代码是相同的,无论绑定表达式是foo.text.length>0
还是foo.text.length()>0
。我也注意到了这一点,但它与工作有区别。我测试了两者,它使用length()
Aha!我现在看到了区别!使用()
,数据绑定正确地生成TextWatcher
,以不断更新启用的属性,而不使用()
,这些行没有生成。我对此进行了归档,好像数据绑定编译器足够聪明,知道为方法调用向长度添加()
,它应该