Android 如何让数据绑定表达式对同一布局中的EditText中的更改作出反应?

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="@

假设我有一个ID为
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
,以不断更新启用的属性,而不使用
()
,这些行没有生成。我对此进行了归档,好像数据绑定编译器足够聪明,知道为方法调用向
长度添加
()
,它应该