[JAVA] How to implement TextInputLayout with validation function

Overview

We will extend Android's TextInputLayout and explain how to implement ValidationTextInputLayout with validation function. ValidationTextInputLayout allows you to specify required, validation items, and error messages from xml by adding custom attributes.

Operation example

animation

The shape you should aim for

In the following, the input field of the email address is required, and it is checked whether the input content is in the email format. If it is not the content of the email, the character string specified by error_text is displayed.

<ValidationTextInputLayout
    app:required="true"
    app:validation_type="email"
    app:error_text="Email value is invalidated"
    >
    <EditText
        android:hint="Email (Required)"
        />
</ValidationTextInputLayout>

How it works

Definition of custom attributes

Define custom attributes in res / values / attrs.xml. ValidationTextInputLayout, which will be defined later, receives attributes and changes the behavior.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ValidationTextInputLayout">
        <attr name="required" format="boolean" />
        <attr name="validation_type">
            <enum name="post_code" value="0" />
            <enum name="email" value="1" />
        </attr>
        <attr name="error_text" format="string" />
    </declare-styleable>
</resources>

Validation type definition

Define ValidationType as an enum. This process is not required, but it improves the visibility of the source code. The value of the enum and the value defined in attrs.xml must match.

public enum ValidationType {
    PostCode(0), Email(1),
    Null(9999);
    private int value;

    ValidationType(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    public static ValidationType valueOf(final int value) {
        ValidationType type = Null;
        for (ValidationType validationType : ValidationType.values()) {
            if (validationType.getValue() == value) {
                type = validationType;
                break;
            }
        }
        return type;
    }
}

TextInputLayout extension

Gets the attribute value specified by initAttrs (). updateError () validates and outputs an error message if necessary. From the outside, you can determine if validation has passed by calling isValidated ().

public class ValidationTextInputLayout extends TextInputLayout {
    private static final String PATTERN_POST_CODE = "\\d{7}";

    private boolean isRequired = false;
    private ValidationType validationType = ValidationType.Null;
    private String errorText;

    public ValidationTextInputLayout(Context context) {
        super(context);
    }

    public ValidationTextInputLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
    }

    public ValidationTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
    }

    private void initAttrs(final Context context, AttributeSet attrs) {
        final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ValidationTextInputLayout);

        isRequired = typedArray.getBoolean(R.styleable.ValidationTextInputLayout_required, false);

        final int validationTypeValue = typedArray.getInt(
                R.styleable.ValidationTextInputLayout_validation_type, ValidationType.Null.getValue());
        validationType = ValidationType.valueOf(validationTypeValue);

        String errorText = typedArray.getString(R.styleable.ValidationTextInputLayout_error_text);
        if (TextUtils.isEmpty(errorText)) {
            errorText = getContext().getString(R.string.error_default_text);
        }
        this.errorText = errorText;
    }

    public boolean isValidated() {
        updateError();

        final boolean isValidated = TextUtils.isEmpty(getError());
        setErrorEnabled(!isValidated);
        return isValidated;
    }

    private void updateError() {
        final String text = getEditText().getText().toString();
        final boolean isEmpty = TextUtils.isEmpty(text);
        setError(null);

        switch (validationType) {
            case PostCode:
                if (!isPostCode(text)) {
                    setError(errorText);
                }
                break;
            case Email:
                if (!isEmail(text)) {
                    setError(errorText);
                }
                break;
            default:
                break;
        }

        if (isEmpty) {
            if (isRequired) {
                setError("Fill in this form");
            } else {
                setError(null);
            }
        }
    }

    private boolean isPostCode(final String str) {
        return Pattern.compile(PATTERN_POST_CODE).matcher(str).matches();
    }

    private boolean isEmail(final String str) {
        return Patterns.EMAIL_ADDRESS.matcher(str).matches();
    }
}

sample

I have a project that works on Validation-Text-Input-Layout @ github.

iOS version

Similar processing is implemented in iOS. Please see Text-Input-Layout @ github.

Recommended Posts

How to implement TextInputLayout with validation function
Try to implement login function with Spring-Boot
[Swift] How to implement the LINE login function
[swift5] How to implement the Twitter share function
How to implement the breadcrumb function using gretel
Try to implement login function with Spring Boot
[For beginners] How to implement the delete function
[Swift] How to implement the fade-in / out function
[Rails] How to easily implement numbers with pull-down
How to implement search function with rails (multiple columns are also supported)
How to implement UICollectionView in Swift with code only
How to add ActionText function
How to make LINE messaging function made with Ruby
How to number (number) with html.erb
How to update with activerecord-import
How to write Rails validation
[Rails] How to use validation
[Rails] How to implement scraping
Rails learning How to implement search function using ActiveModel
[Java] How to implement multithreading
Implement search function with form_with
How to scroll horizontally with ScrollView
How to get started with slim
How to specify validation for time_field
How to enclose any character with "~"
Try to implement iOS14 Widget function
How to use mssql-tools with alpine
[Rails] How to implement star rating
How to get along with Rails
How to add the delete function
How to start Camunda with Docker
[Swift] How to implement the Twitter login function using Firebase UI ①
I tried to implement the image preview function with Rails / jQuery
[Behavior confirmed in December 2020] How to implement the alert display function
[Swift] How to implement the Twitter login function using Firebase UI ②
How to use MinIO with the same function as S3 Use docker-compose
How to crop an image with libGDX
How to adjustTextPosition with iOS Keyboard Extension
How to share files with Docker Toolbox
How to implement date calculation in Java
How to implement Kalman filter in Java
How to compile Java with VsCode & Ant
[Java] How to use the hasNext function
[Java] How to compare with equals method
[Android] How to deal with dark themes
How to use BootStrap with Play Framework
[Rails] How to use rails console with docker
How to switch thumbnail images with JavaScript
[Note] How to get started with Rspec
How to do API-based control with cancancan
[Swift] Easy to implement modal with PanModal
How to achieve file download with Feign
How to implement coding conventions in Java
How to update related models with accepts_nested_attributes_for
How to set JAVA_HOME with Maven appassembler-maven-plugin
[Swift5] How to implement standby screen using'PKHUD'
How to handle sign-in errors with devise
How to implement ranking functionality in Rails
[Processing × Java] How to use the function
How to delete data with foreign key
How to test private scope with JUnit