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

Com*_*are 5 android android-databinding

假设我有EditText一个 ID 为foo. 在同一个布局资源的其他地方,我有一个Button,并且我想Button仅当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}" />
Run Code Online (Sandbox Code Playgroud)

生成的绑定类确实根据...中的文本长度调用setEnabled(),但仅在调用时调用。这似乎不是在用户键入时调用的,因此 my 的启用状态不会根据用户在.barfooexecuteBindings()ButtonEditText

我可以解决这个问题,但感觉这应该有效。有什么我想念的吗?这是一个已知的限制吗?

Khe*_*raj 4

更新

只需更改foo.text.lengthfoo.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);
    }
}
Run Code Online (Sandbox Code Playgroud)

原因是,当您使用text.lengththen 时,您需要在更改时调用所有依赖元素。因为text.length是不可观察的,所以需要手动调用它。生成的绑定类调用setName(value),但它不会更改text.length依赖视图。

2. 使用MutableLiveData

如果您使用MutableLiveData,则需要提供LifeCycleOwner

    binding.setLifecycleOwner(this);
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我使用其中 3 个解决方案创建了一个示例,所有这些解决方案都有效!

活动登录.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>
Run Code Online (Sandbox Code Playgroud)

登录活动.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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我将所有模型都放在 Activity 中。我尽力解释得很好,如果您有任何困惑,仍然可以发表评论。

输出

输出图像

  • 啊哈!我现在看到区别了!使用“()”,数据绑定可以正确生成“TextWatcher”以不断更新启用的属性——如果没有“()”,则不会生成这些行。我对此提交了[错误报告](https://issuetracker.google.com/issues/116536168),就好像数据绑定编译器足够聪明,知道将“()”添加到该方法的“length”中调用时,它应该知道添加 `TextWatcher`。非常感谢! (2认同)