目前,OTUS为新课程“ Android Developer。Basic”开设了一套课程。在课程开始前夕,我们通常会为您准备一份有趣的翻译,我们还为您提供观看课程开放日的机会,您将在其中详细了解学习过程并获得问题的答案。
验证表单的便捷方法
“要学好东西,就必须学会几种方法。”
几天前,我正在一个项目中,需要实施表单元素验证textInputLayout
并textInputEditText
使用数据绑定。不幸的是,有关此主题的文档很少。
最后,通过研究一些材料并进行了一系列实验,我获得了预期的结果。这就是我想要得到的:
, . , .
?
, , .
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>
. .
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
, - . ! !