Validation des éléments de formulaire textInputLayout dans Android à l'aide de la liaison de données

À l'heure actuelle, OTUS a ouvert un ensemble pour le nouveau cours "Développeur Android. Basique" . À la veille du début du cours, nous avons traditionnellement préparé une traduction intéressante pour vous, et nous vous proposons également de regarder la journée portes ouvertes pour le cours, au cours de laquelle vous apprendrez en détail le processus d'apprentissage et obtiendrez des réponses à vos questions .


Moyen pratique de valider les formulaires

"Pour bien apprendre quelque chose, il faut apprendre à le faire de plusieurs manières."

Il y a quelques jours, je travaillais sur un projet dans lequel je devais implémenter la validation des éléments de formulaire textInputLayoutet textInputEditTextutiliser la liaison de données. Malheureusement, peu de documentation est disponible sur ce sujet.

Au final, j'ai obtenu le résultat souhaité en étudiant certains matériaux et en menant une série d'expériences. C'est ce que je voulais obtenir:

 

Vue finale de l'application

, . , .

?

  1. Kotlin

  2. Material

, , .

1. build.gradle(:app), android{} :

dataBinding{    
    enabled true
}

textInputLayout textInputEditText Material Android, build.gradle(:app) :

implementation 'com.google.android.material:material:1.2.1'

. ,  — , .

:

 

activity_main.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"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        android:orientation="vertical"
        tools:context=".MainActivity">


        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/userNameTextInputLayout"
            style="@style/TextInputLayoutBoxColor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:hint="@string/username"
            app:endIconMode="clear_text"
            app:errorEnabled="true"
            app:hintTextAppearance="@style/TextAppearance.App.TextInputLayout">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/userName"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:inputType="textPersonName" />


        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/emailTextInputLayout"
            style="@style/TextInputLayoutBoxColor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:hint="@string/email"
            app:endIconMode="clear_text"
            app:errorEnabled="true"
            app:hintTextAppearance="@style/TextAppearance.App.TextInputLayout">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/email"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:inputType="textEmailAddress" />


        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/passwordTextInputLayout"
            style="@style/TextInputLayoutBoxColor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:hint="@string/password"
            app:errorEnabled="true"
            app:hintTextAppearance="@style/TextAppearance.App.TextInputLayout"
            app:passwordToggleEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/password"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:inputType="textPassword" />


        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/confirmPasswordTextInputLayout"
            style="@style/TextInputLayoutBoxColor"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:hint="@string/confirm_password"
            app:errorEnabled="true"
            app:hintTextAppearance="@style/TextAppearance.App.TextInputLayout"
            app:passwordToggleEnabled="true">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/confirmPassword"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:inputType="textPassword"
                app:passwordToggleEnabled="true" />


        </com.google.android.material.textfield.TextInputLayout>

        <com.google.android.material.button.MaterialButton
            android:id="@+id/loginButton"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/login"
            android:textAllCaps="false" />

    </LinearLayout>
</layout>

<layout>,  — .

. .

2. GIF-, (. ), , , true. , TextWatcher, .

MainActivity.kt , TextWatcher:

/**
     * applying text watcher on each text field
     */
    inner class TextFieldValidation(private val view: View) : TextWatcher {
        override fun afterTextChanged(s: Editable?) {}
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            // checking ids of each text field and applying functions accordingly.

        }

    }

view, , .

3. . , true . , , :

  /**
     * field must not be empy
     */
    private fun validateUserName(): Boolean {
        if (binding.userName.text.toString().trim().isEmpty()) {
            binding.userNameTextInputLayout.error = "Required Field!"
            binding.userName.requestFocus()
            return false
        } else {
            binding.userNameTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) text should matches email address format
     */
    private fun validateEmail(): Boolean {
        if (binding.email.text.toString().trim().isEmpty()) {
            binding.emailTextInputLayout.error = "Required Field!"
            binding.email.requestFocus()
            return false
        } else if (!isValidEmail(binding.email.text.toString())) {
            binding.emailTextInputLayout.error = "Invalid Email!"
            binding.email.requestFocus()
            return false
        } else {
            binding.emailTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) password lenght must not be less than 6
     * 3) password must contain at least one digit
     * 4) password must contain atleast one upper and one lower case letter
     * 5) password must contain atleast one special character.
     */
    private fun validatePassword(): Boolean {
        if (binding.password.text.toString().trim().isEmpty()) {
            binding.passwordTextInputLayout.error = "Required Field!"
            binding.password.requestFocus()
            return false
        } else if (binding.password.text.toString().length < 6) {
            binding.passwordTextInputLayout.error = "password can't be less than 6"
            binding.password.requestFocus()
            return false
        } else if (!isStringContainNumber(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error = "Required at least 1 digit"
            binding.password.requestFocus()
            return false
        } else if (!isStringLowerAndUpperCase(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error =
                "Password must contain upper and lower case letters"
            binding.password.requestFocus()
            return false
        } else if (!isStringContainSpecialCharacter(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error = "1 special character required"
            binding.password.requestFocus()
            return false
        } else {
            binding.passwordTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) password and confirm password should be same
     */
    private fun validateConfirmPassword(): Boolean {
        when {
            binding.confirmPassword.text.toString().trim().isEmpty() -> {
                binding.confirmPasswordTextInputLayout.error = "Required Field!"
                binding.confirmPassword.requestFocus()
                return false
            }
            binding.confirmPassword.text.toString() != binding.password.text.toString() -> {
                binding.confirmPasswordTextInputLayout.error = "Passwords don't match"
                binding.confirmPassword.requestFocus()
                return false
            }
            else -> {
                binding.confirmPasswordTextInputLayout.isErrorEnabled = false
            }
        }
        return true
    }

4. textWatcher, :

 private fun setupListeners() {
        binding.userName.addTextChangedListener(TextFieldValidation(binding.userName))
        binding.email.addTextChangedListener(TextFieldValidation(binding.email))
        binding.password.addTextChangedListener(TextFieldValidation(binding.password))
        binding.confirmPassword.addTextChangedListener(TextFieldValidation(binding.confirmPassword))
    }

TextFieldValidation , ? , , TextFieldValidation:

//        

, view TextFieldValidation, :

/**
     * applying text watcher on each text field
     */
    inner class TextFieldValidation(private val view: View) : TextWatcher {
        override fun afterTextChanged(s: Editable?) {}
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            // checking ids of each text field and applying functions accordingly.
            when (view.id) {
                R.id.userName -> {
                    validateUserName()
                }
                R.id.email -> {
                    validateEmail()
                }
                R.id.password -> {
                    validatePassword()
                }
                R.id.confirmPassword -> {
                    validateConfirmPassword()
                }
            }
        }
    }

MainActivity.kt :

package com.example.textinputlayoutformvalidation

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.util.Patterns
import android.view.View
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import com.example.textinputlayoutformvalidation.FieldValidators.isStringContainNumber
import com.example.textinputlayoutformvalidation.FieldValidators.isStringContainSpecialCharacter
import com.example.textinputlayoutformvalidation.FieldValidators.isStringLowerAndUpperCase
import com.example.textinputlayoutformvalidation.FieldValidators.isValidEmail
import com.example.textinputlayoutformvalidation.databinding.ActivityMainBinding

/**
 * created by : Mustufa Ansari
 * Email : mustufaayub82@gmail.com
 */

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        setupListeners()

        binding.loginButton.setOnClickListener {
            if (isValidate()) {
                Toast.makeText(this, "validated", Toast.LENGTH_SHORT).show()
            }
        }
    }

    private fun isValidate(): Boolean =
        validateUserName() && validateEmail() && validatePassword() && validateConfirmPassword()

    private fun setupListeners() {
        binding.userName.addTextChangedListener(TextFieldValidation(binding.userName))
        binding.email.addTextChangedListener(TextFieldValidation(binding.email))
        binding.password.addTextChangedListener(TextFieldValidation(binding.password))
        binding.confirmPassword.addTextChangedListener(TextFieldValidation(binding.confirmPassword))
    }

    /**
     * field must not be empy
     */
    private fun validateUserName(): Boolean {
        if (binding.userName.text.toString().trim().isEmpty()) {
            binding.userNameTextInputLayout.error = "Required Field!"
            binding.userName.requestFocus()
            return false
        } else {
            binding.userNameTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) text should matches email address format
     */
    private fun validateEmail(): Boolean {
        if (binding.email.text.toString().trim().isEmpty()) {
            binding.emailTextInputLayout.error = "Required Field!"
            binding.email.requestFocus()
            return false
        } else if (!isValidEmail(binding.email.text.toString())) {
            binding.emailTextInputLayout.error = "Invalid Email!"
            binding.email.requestFocus()
            return false
        } else {
            binding.emailTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) password lenght must not be less than 6
     * 3) password must contain at least one digit
     * 4) password must contain atleast one upper and one lower case letter
     * 5) password must contain atleast one special character.
     */
    private fun validatePassword(): Boolean {
        if (binding.password.text.toString().trim().isEmpty()) {
            binding.passwordTextInputLayout.error = "Required Field!"
            binding.password.requestFocus()
            return false
        } else if (binding.password.text.toString().length < 6) {
            binding.passwordTextInputLayout.error = "password can't be less than 6"
            binding.password.requestFocus()
            return false
        } else if (!isStringContainNumber(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error = "Required at least 1 digit"
            binding.password.requestFocus()
            return false
        } else if (!isStringLowerAndUpperCase(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error =
                "Password must contain upper and lower case letters"
            binding.password.requestFocus()
            return false
        } else if (!isStringContainSpecialCharacter(binding.password.text.toString())) {
            binding.passwordTextInputLayout.error = "1 special character required"
            binding.password.requestFocus()
            return false
        } else {
            binding.passwordTextInputLayout.isErrorEnabled = false
        }
        return true
    }

    /**
     * 1) field must not be empty
     * 2) password and confirm password should be same
     */
    private fun validateConfirmPassword(): Boolean {
        when {
            binding.confirmPassword.text.toString().trim().isEmpty() -> {
                binding.confirmPasswordTextInputLayout.error = "Required Field!"
                binding.confirmPassword.requestFocus()
                return false
            }
            binding.confirmPassword.text.toString() != binding.password.text.toString() -> {
                binding.confirmPasswordTextInputLayout.error = "Passwords don't match"
                binding.confirmPassword.requestFocus()
                return false
            }
            else -> {
                binding.confirmPasswordTextInputLayout.isErrorEnabled = false
            }
        }
        return true
    }

    /**
     * applying text watcher on each text field
     */
    inner class TextFieldValidation(private val view: View) : TextWatcher {
        override fun afterTextChanged(s: Editable?) {}
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            // checking ids of each text field and applying functions accordingly.
            when (view.id) {
                R.id.userName -> {
                    validateUserName()
                }
                R.id.email -> {
                    validateEmail()
                }
                R.id.password -> {
                    validatePassword()
                }
                R.id.confirmPassword -> {
                    validateConfirmPassword()
                }
            }
        }
    }
}

:

 

:

https://github.com/Mustufa786/TextInputLayout-FormValidation

, - . ! !

.




All Articles