I made the binding as my answer to How to set an error in EditText using DataBinding Framwork MVVM . But this time, he used TextInputLayout as a sample, like the previous one.
The goals of this idea are:
- Make xml as convenient and independent as possible
- Regardless of action-side validation and xml-side validation
Of course you can do your own validation and set it using the <variable> in xml
Firstly, it implements the static method of binding and the corresponding rules for checking the string for preparation.
Snap
@BindingAdapter({"app:validation", "app:errorMsg"}) public static void setErrorEnable(TextInputLayout textInputLayout, StringRule stringRule, final String errorMsg) { }
StringRule
public static class Rule { public static StringRule NOT_EMPTY_RULE = s -> TextUtils.isEmpty(s.toString()); public static StringRule EMAIL_RULE = s -> s.toString().length() > 18; } public interface StringRule { boolean validate(Editable s); }
Secondly, put the default error message and error message in TextInputLayout and simplify checking it, binding in xml
<android.support.design.widget.TextInputLayout android:id="@+id/imageUrlValidation" android:layout_width="match_parent" android:layout_height="wrap_content" app:validation="@{Rule.NOT_EMPTY_RULE}" app:errorMsg='@{"Cannot be empty"}' > <android.support.design.widget.TextInputEditText android:id="@+id/input_imageUrl" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Image Url" android:text="@={feedEntry.imageUrl}" /> </android.support.design.widget.TextInputLayout>
Thirdly, when you click the button, you can use the predefined identifier in TextInputLayout (for example, imageUrlValidation) to perform a final activity check
Button button = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); button.setOnClickListener(view1 -> { // TODO Do something //to trigger auto error enable FeedEntry inputFeedEntry = dialogFeedEntryBinding.getFeedEntry(); Boolean[] validations = new Boolean[]{ dialogFeedEntryBinding.imageUrlValidation.isErrorEnabled(), dialogFeedEntryBinding.titleValidation.isErrorEnabled(), dialogFeedEntryBinding.subTitleValidation.isErrorEnabled() }; boolean isValid = true; for (Boolean validation : validations) { if (validation) { isValid = false; } } if (isValid) { new AsyncTask<FeedEntry, Void, Void>() { @Override protected Void doInBackground(FeedEntry... feedEntries) { viewModel.insert(feedEntries); return null; } }.execute(inputFeedEntry); dialogInterface.dismiss(); } });
The full code is as follows:
dialog_feedentry.xml
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> <import type="com.example.common.components.TextInputEditTextBindingUtil.Rule" /> <variable name="feedEntry" type="com.example.feedentry.repository.bean.FeedEntry" /> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical"> <android.support.design.widget.TextInputLayout android:id="@+id/imageUrlValidation" android:layout_width="match_parent" android:layout_height="wrap_content" app:validation="@{Rule.NOT_EMPTY_RULE}" app:errorMsg='@{"Cannot be empty"}' > <android.support.design.widget.TextInputEditText android:id="@+id/input_imageUrl" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Image Url" android:text="@={feedEntry.imageUrl}" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/titleValidation" android:layout_width="match_parent" android:layout_height="wrap_content" app:validation="@{Rule.NOT_EMPTY_RULE}" app:errorMsg='@{"Cannot be empty"}' > <android.support.design.widget.TextInputEditText android:id="@+id/input_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Title" android:text="@={feedEntry.title}" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/subTitleValidation" android:layout_width="match_parent" android:layout_height="wrap_content" app:validation="@{Rule.NOT_EMPTY_RULE}" app:errorMsg='@{"Cannot be empty"}' > <android.support.design.widget.TextInputEditText android:id="@+id/input_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Subtitle" android:text="@={feedEntry.subTitle}" /> </android.support.design.widget.TextInputLayout> </LinearLayout> </layout>
TextInputEditTextBindingUtil.java
package com.example.common.components; import android.databinding.BindingAdapter; import android.support.design.widget.TextInputLayout; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; public class TextInputEditTextBindingUtil { @BindingAdapter({"app:validation", "app:errorMsg"}) public static void setErrorEnable(TextInputLayout textInputLayout, StringRule stringRule, final String errorMsg) { textInputLayout.getEditText().addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void afterTextChanged(Editable editable) { textInputLayout .setErrorEnabled(stringRule.validate(textInputLayout.getEditText().getText())); if (stringRule.validate(textInputLayout.getEditText().getText())) { textInputLayout.setError(errorMsg); } else { textInputLayout.setError(null); } } }); textInputLayout .setErrorEnabled(stringRule.validate(textInputLayout.getEditText().getText())); if (stringRule.validate(textInputLayout.getEditText().getText())) { textInputLayout.setError(errorMsg); } else { textInputLayout.setError(null); } } public static class Rule { public static StringRule NOT_EMPTY_RULE = s -> TextUtils.isEmpty(s.toString()); public static StringRule EMAIL_RULE = s -> s.toString().length() > 18; } public interface StringRule { boolean validate(Editable s); } }
FeedActivity.java
public class FeedActivity extends AppCompatActivity { private FeedEntryListViewModel viewModel; @SuppressLint("StaticFieldLeak") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_feed); viewModel = ViewModelProviders.of(this) .get(FeedEntryListViewModel.class); viewModel.init(this); ViewPager viewPager = findViewById(R.id.viewpager); setupViewPager(viewPager);