如何使用DataBinding Framework MVVM在EditText上设置错误

Pra*_*nav 11 android mvvm android-databinding

我正在使用Android数据绑定框架我假设一个EditText用于登录表单,用户名如下所示

<EditText
        android:id="@+id/etext_uname"
        style="@style/login_edittext"
        android:hint="@string/hint_username"
        android:inputType="textEmailAddress" />
Run Code Online (Sandbox Code Playgroud)

我也定义了LoginViewModel但我需要帮助如何在用户输入错误的电子邮件地址时在edittext中设置错误在某些事件中让我们说

public void afterTextChanged(@NonNull final Editable editable)
Run Code Online (Sandbox Code Playgroud)

因为据我所知,在传统Android方法中我们可以通过et.setError()方法以编程方式执行此操作,但我不想通过Activity或Fragment创建edittext对象.

Lon*_*ger 7

如果你想EditText.setError()用数据绑定做一些功能,这里有两个方法.

方法1

使用从数据绑定生成的最终EditText视图(https://developer.android.com/topic/libraries/data-binding/index.html#views_with_ids)

您可以直接调用EditText而无需手动创建它,因为它是在您为视图设置id后自动生成的(对于包含的布局也是如此).

MainActivityBinding.etext_uname.setError("Wrong email format");
Run Code Online (Sandbox Code Playgroud)

要么

MainActivityBinding.etext_uname.addTextChangedListener(new MyOwnTextWatcher());
Run Code Online (Sandbox Code Playgroud)

方法2

如果你想像乔治亚提到的那样使用xml的绑定方法(https://medium.com/google-developers/android-data-binding-custom-setters-55a25a7aea47#.su88ujqrn)

首先,您必须设置自己的绑定方法.建议为所有绑定方法创建另一个类.

方法必须是静态的,带有@BindingAdapter注释和相应的绑定方法名称(Namespace和方法名称可以自定义)

1.设置自定义TextWatcher

public class MyOwnBindingUtil {
    public interface StringRule {
        public boolean validate(Editable s);
    }
    @BindingAdapter("android:watcher")
    public static void bindTextWatcher(EditText pEditText, TextWatcher pTextWatcher) {
        pEditText.addTextChangedListener(pTextWatcher);
    }
    @BindingAdapter(value = {"email:rule", "email:errorMsg"}, requireAll = true)
    public static void bindTextChange(final EditText pEditText, final StringRule pStringRule, final String msg) {
        pEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                }
                @Override
                public void afterTextChanged(Editable s) {
                    if (!pStringRule.validate(s)) {
                        pEditText.setError(msg);
                }
            }
        });
    }
    /*
    Your other custom binding method
     */
}
Run Code Online (Sandbox Code Playgroud)

如果要使用自定义操作设置自己的TextWatcher,如显示的Toast,则显示Dialog.你应该使用"android:watcher"方法

mBinding.setWatcher(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    }
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
    }
    @Override
    public void afterTextChanged(Editable s) {
    }
});
Run Code Online (Sandbox Code Playgroud)

在xml中,

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:email="http://schemas.android.com/tools"
    >

    <data>
        <variable
            name="watcher"
            type="android.text.TextWatcher"/>
        <variable
            name="emailRule"
            type="example.com.testerapplication.MyOwnBindingUtil.StringRule"/>
        <variable
            name="errorMsg"
            type="java.lang.String"/>
    </data>
    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Input Email"
        android:watcher="@{watcher}
        />
Run Code Online (Sandbox Code Playgroud)

2.设置您自己的验证规则和错误消息

如果你想使用setError函数,只留下errorMsg和验证逻辑进行自定义.您可以像下面那样设置xml.

在xml中,

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:email="http://schemas.android.com/tools"
    >

    <data>
        <variable
            name="watcher"
            type="android.text.TextWatcher"/>
        <variable
            name="emailRule"
            type="example.com.testerapplication.MyOwnBindingUtil.StringRule"/>
        <variable
            name="errorMsg"
            type="java.lang.String"/>
    </data>
    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Input Email"
        email:rule="@{emailRule}"
        email:errorMsg="@{errorMsg}"
        />
Run Code Online (Sandbox Code Playgroud)

活动代码

mBinding.setErrorMsg("Wrong type");
mBinding.setEmailRule(new MyOwnBindingUtil.StringRule() {
    @Override
    public boolean validate(Editable s) {
        // check if the length of string is larger than 18  
        return s.toString().length() > 18;
    }
});
Run Code Online (Sandbox Code Playgroud)

请随意编辑我的代码,使开发人员使用的绑定更通用.


Man*_*ari 5

从根本上来说,您需要一种实现依赖字段的方法。错误取决于文本的值。您希望在文本更改时更新错误值。

我找到了两种方法来实现这一目标:

使用数据绑定表达式设置属性

<EditView
    android:text="@={viewModel.email}"
    android:error="@={viewModel.emailRule.check(email)} />
Run Code Online (Sandbox Code Playgroud)

数据绑定确保每当更改check时都会调用该函数。email

使用 RxJava 将一个字段转换为另一个字段

我编写了一个实用程序来在ObservableField和之间进行转换Observable。参见FieldUtils.java

使用它,您可以在 ViewModel/Model 代码中实现。

public class ViewModel {
    ObservableField<String> email = new ObservableField<>();
    ObservableField<String> emailError = toField(toObservable(email).map(new Func1<String, String>() {
            @Override
            public String call(String email) {
                return FormUtils.checkEmail(email) ? null : "Invalid Email";
            }
        }));
}
Run Code Online (Sandbox Code Playgroud)

编辑文本的问题

EditText 在用户键入时清除错误。数据绑定期望在调用 setter 后保留属性的值。因此,如果值没有改变,它不会再次调用 setter。因此,只要您输入,如果计算出的错误值相同,数据绑定将不会调用 setter,因此错误将消失。这种类型使得error属性与数据绑定不兼容。

我更喜欢使用设计库提供的TextInputLayout 。它有一个持久的错误字段,而且看起来也更好。