如何解决DataBindig 将错误的 onFocusChangeListener 返回到布局
我有一个登录表单验证机制。电子邮件和密码有两个 TextInputEditText,它们都附加到各自的 onFocusChangeListeners,DataBinding 用于设置它们,但 DataBinding 返回错误的侦听器。
表格如下:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="loginViewModel"
type="com.example.increaseyouriq.ui.forms.LoginFormViewModel" />
</data>
<LinearLayout
android:id="@+id/ll_login"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/parent.contentLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="26dp">
<com.google.android.material.card.MaterialCardView
style="@style/cardOutline"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
style="@style/viewParent.headerText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_title" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
style="@style/textInputStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/enter_email"
error="@{loginViewModel.loginForm.emailError}"
app:errorEnabled="@{loginViewModel.loginForm.isEmailError()}"
app:endIconMode="clear_text">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_login_email"
style="@style/textInputEditext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
onFocus="@{loginViewModel.onFocusEmailChangeListener}"
android:text="@={loginViewModel.loginFields.email}"
android:inputType="textNoSuggestions|textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/textInputStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/enter_password"
error="@{loginViewModel.loginForm.passwordError}"
app:errorEnabled="@{loginViewModel.loginForm.isPasswordError()}"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
style="@style/textInputEditext"
android:id="@+id/et_login_password"
onFocus="@{loginViewModel.onFocusPasswordChangeListener}"
android:text="@={loginViewModel.loginFields.password}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</layout>
这是我的LoginFormViewModel.java:
public class LoginFormViewModel extends ViewModel {
private static final String LOG_TAG = "LoginFormViewModel";
private View.OnFocusChangeListener onFocusEmail;
private View.OnFocusChangeListener onFocusPassword;
public void init() {
loginForm = new LoginForm();
onFocusPassword = (v,hasFocus) -> {
TextInputEditText et = (TextInputEditText) v;
MyUtilsApp.showLog(LOG_TAG,String.format("%s password listener attached to :%d",String.valueOf(et.getText()),et.getId()));
if (et.getText().length() > 0 && !hasFocus) {
loginForm.isPasswordValid(true);
}
};
onFocusEmail = (v,hasFocus) -> {
TextInputEditText et = (TextInputEditText) v;
MyUtilsApp.showLog(LOG_TAG,"email listener attached");
if (et.getText().length() > 0 && !hasFocus) {
loginForm.isEmailValid(true);
}
};
}
public View.OnFocusChangeListener getOnFocusEmailChangeListener() {
return onFocusEmail;
}
public View.OnFocusChangeListener getOnFocusPasswordChangeListener() {
return onFocusPassword;
}
@BindingAdapter("onFocus")
public static void bindFocusChange(TextInputEditText editText,View.OnFocusChangeListener onFocusChangeListener) {
if (editText.getOnFocusChangeListener() == null) {
editText.setOnFocusChangeListener(onFocusChangeListener);
}
}
}
这是我的LoginActivity.java:
public class LoginActivity extends AppCompatActivity {
private static final String LOG_TAG = "LoginActivity";
ActivityLoginBinding binding;
private LoginRegisterViewModel loginRegisterViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_login);
setupBindings(savedInstanceState);
}
private void setupBindings(Bundle savedInstanceState) {
LoginFormViewModel loginFormViewModel = new ViewModelProvider(this).get(LoginFormViewModel.class);
if(savedInstanceState==null)
loginFormViewModel.init();
binding.setLoginViewModel(loginFormViewModel);
binding.setLifecycleOwner(this);
loginFormViewModel.getLoginFields().observe(this,loginFields -> {
Toast.makeText(LoginActivity.this,"Email " + loginFields.getEmail() + ",Password " + loginFields.getPassword(),Toast.LENGTH_SHORT).show();
});
binding.inLayoutLogin.btnLoginLogin.setOnClickListener(view -> {
binding.executePendingBindings();
loginFormViewModel.getLoginForm().onClick();
});
}
}
很明显,我将两个侦听器都设置为 onFocusEmail 类型,只是因为 onFocusPassword 在运行时被附加到两个 TextInputEditTexts 上。 以下是日志:
com.example.increaseyouriq E/LoginFormViewModel: password listener attached to :2131296499
com.example.increaseyouriq E/LoginFormViewModel: ttf password listener attached to :2131296499
onFocusEmail 无处可见,它已在运行时附加。 有关代码的更多详细信息,请参阅 here
解决方法
我对你的代码做了一些实验,我相信我找到了根本原因。
问题:
您的听众都没有附加到您的电子邮件字段 (TextInputEditText "et_login_email")。
原因:
原因是你这里有一个空检查;
@BindingAdapter("onFocus")
public static void bindFocusChange(TextInputEditText editText,View.OnFocusChangeListener onFocusChangeListener) {
if (editText.getOnFocusChangeListener() == null) {
editText.setOnFocusChangeListener(onFocusChangeListener);
}
}
并且您的电子邮件字段已经有一个由 "app:endIconMode="clear_text"" 属性设置的 onFocusChangeListener。
<com.google.android.material.textfield.TextInputLayout
...
android:hint="@string/enter_email"
..."
app:endIconMode="clear_text">
您不能为 email 字段设置侦听器,因为它的侦听器从一开始就不是空的,并且当前方法 (bindFocusChange()) 仅在它为空时才设置它。
解决方案 1:
在设置 onFocusChangeListeners 时删除空检查。
解决方案 2:
以更少的代码使用数据绑定库的 automatic method selection。
将自定义属性的名称“onFocus”更改为“onFocusChangeListener”。由于 TextInputEditText 字段具有与此名称匹配的 setter 方法 (setOnFocusChangeListener),库可以自动处理此问题,您可以完全删除“bindFocusChange(...)”方法:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。