Hola amigos 👋 Bienvenidos a un nuevo tutorial de Universo Android. Hoy aprenderemos a trabajar con EditText y validaciones de formulario, componentes esenciales para capturar y validar datos del usuario de forma profesional.
Al finalizar este tutorial tendrás una aplicación que incluirá:
- EditText con diferentes tipos de entrada
- Validaciones en tiempo real
- Patrones de validación (email, teléfono, contraseña)
- Mensajes de error personalizados
- TextInputLayout con Material Design
- Formularios completos y funcionales
🟩 1. ¿Qué es EditText?
EditText es el componente que permite a los usuarios ingresar texto. Soporta diferentes tipos de entrada (texto, números, email, contraseña) y puede ser validado para garantizar datos correctos.
🟩 2. Tipos de InputType
- text: Texto normal
- textEmailAddress: Correo electrónico
- textPassword: Contraseña
- number: Solo números
- phone: Teléfono
- textMultiLine: Múltiples lÃneas
🟩 3. Crear el Proyecto
Creamos un nuevo proyecto en Android Studio con Empty Activity.
🟩 4. Agregar Dependencias
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
}🟩 5. Diseño XML Principal
📄 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Formulario de Registro"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="#2196F3"
android:layout_marginBottom="24dp" />
<!-- TextInputLayout para Nombre -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nombre completo"
app:startIconDrawable="@android:drawable/ic_menu_myplaces"
app:endIconMode="clear_text"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName" />
</com.google.android.material.textfield.TextInputLayout>
<!-- TextInputLayout para Email -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Correo electrónico"
app:startIconDrawable="@android:drawable/ic_dialog_email"
app:endIconMode="clear_text"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress" />
</com.google.android.material.textfield.TextInputLayout>
<!-- TextInputLayout para Contraseña -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Contraseña"
app:startIconDrawable="@android:drawable/ic_lock_idle_lock"
app:endIconMode="password_toggle"
app:helperText="MÃnimo 6 caracteres"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<!-- TextInputLayout para Teléfono -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Teléfono"
app:startIconDrawable="@android:drawable/stat_sys_phone_call"
app:prefixText="+504 "
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="phone" />
</com.google.android.material.textfield.TextInputLayout>
<!-- TextInputLayout para Edad -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilAge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Edad"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_marginTop="16dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/txtAge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Botón Registrar -->
<Button
android:id="@+id/btnRegister"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Registrar"
android:layout_marginTop="24dp" />
<!-- TextView Resultado -->
<TextView
android:id="@+id/txtResult"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:layout_marginTop="16dp"
android:visibility="gone" />
</LinearLayout>
</ScrollView>🟩 6. MainActivity con Validaciones
📄 MainActivity.java
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.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
public class MainActivity extends AppCompatActivity {
TextInputLayout tilName, tilEmail, tilPassword, tilPhone, tilAge;
TextInputEditText txtName, txtEmail, txtPassword, txtPhone, txtAge;
Button btnRegister;
TextView txtResult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeViews();
setupRealtimeValidation();
btnRegister.setOnClickListener(v -> validateForm());
}
private void initializeViews() {
tilName = findViewById(R.id.tilName);
tilEmail = findViewById(R.id.tilEmail);
tilPassword = findViewById(R.id.tilPassword);
tilPhone = findViewById(R.id.tilPhone);
tilAge = findViewById(R.id.tilAge);
txtName = findViewById(R.id.txtName);
txtEmail = findViewById(R.id.txtEmail);
txtPassword = findViewById(R.id.txtPassword);
txtPhone = findViewById(R.id.txtPhone);
txtAge = findViewById(R.id.txtAge);
btnRegister = findViewById(R.id.btnRegister);
txtResult = findViewById(R.id.txtResult);
}
private void setupRealtimeValidation() {
// Validación de Email en tiempo real
txtEmail.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
validateEmailRealtime(s.toString());
}
@Override
public void afterTextChanged(Editable s) {}
});
// Validación de Contraseña en tiempo real
txtPassword.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
validatePasswordRealtime(s.toString());
}
@Override
public void afterTextChanged(Editable s) {}
});
}
private void validateEmailRealtime(String email) {
if (!email.isEmpty() && !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
tilEmail.setError("Email inválido");
} else {
tilEmail.setError(null);
}
}
private void validatePasswordRealtime(String password) {
if (!password.isEmpty() && password.length() < 6) {
tilPassword.setError("MÃnimo 6 caracteres");
} else {
tilPassword.setError(null);
}
}
private void validateForm() {
boolean isValid = true;
StringBuilder errors = new StringBuilder();
// Limpiar errores
tilName.setError(null);
tilEmail.setError(null);
tilPassword.setError(null);
tilPhone.setError(null);
tilAge.setError(null);
// Validar Nombre
String name = txtName.getText().toString().trim();
if (name.isEmpty()) {
tilName.setError("El nombre es obligatorio");
errors.append("• Ingresa tu nombre\n");
isValid = false;
} else if (name.length() < 3) {
tilName.setError("MÃnimo 3 caracteres");
errors.append("• El nombre es muy corto\n");
isValid = false;
}
// Validar Email
String email = txtEmail.getText().toString().trim();
if (email.isEmpty()) {
tilEmail.setError("El email es obligatorio");
errors.append("• Ingresa tu email\n");
isValid = false;
} else if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
tilEmail.setError("Email inválido");
errors.append("• El email no es válido\n");
isValid = false;
}
// Validar Contraseña
String password = txtPassword.getText().toString();
if (password.isEmpty()) {
tilPassword.setError("La contraseña es obligatoria");
errors.append("• Ingresa una contraseña\n");
isValid = false;
} else if (password.length() < 6) {
tilPassword.setError("MÃnimo 6 caracteres");
errors.append("• La contraseña es muy corta\n");
isValid = false;
} else if (!password.matches(".*[A-Z].*")) {
tilPassword.setError("Debe contener una mayúscula");
errors.append("• Falta una mayúscula\n");
isValid = false;
} else if (!password.matches(".*[0-9].*")) {
tilPassword.setError("Debe contener un número");
errors.append("• Falta un número\n");
isValid = false;
}
// Validar Teléfono
String phone = txtPhone.getText().toString().trim();
if (phone.isEmpty()) {
tilPhone.setError("El teléfono es obligatorio");
errors.append("• Ingresa tu teléfono\n");
isValid = false;
} else if (phone.length() < 8) {
tilPhone.setError("Teléfono inválido");
errors.append("• El teléfono es muy corto\n");
isValid = false;
}
// Validar Edad
String ageStr = txtAge.getText().toString().trim();
if (ageStr.isEmpty()) {
tilAge.setError("La edad es obligatoria");
errors.append("• Ingresa tu edad\n");
isValid = false;
} else {
try {
int age = Integer.parseInt(ageStr);
if (age < 18 || age > 100) {
tilAge.setError("Edad debe estar entre 18 y 100");
errors.append("• Edad fuera de rango\n");
isValid = false;
}
} catch (NumberFormatException e) {
tilAge.setError("Edad inválida");
errors.append("• Edad no válida\n");
isValid = false;
}
}
// Mostrar resultado
txtResult.setVisibility(View.VISIBLE);
if (isValid) {
txtResult.setBackgroundColor(0xFFE8F5E9);
txtResult.setTextColor(0xFF4CAF50);
txtResult.setText("✅ Formulario válido\n\nDatos:\n" +
"Nombre: " + name + "\n" +
"Email: " + email + "\n" +
"Teléfono: " + phone + "\n" +
"Edad: " + ageStr);
Toast.makeText(this, "Registro exitoso", Toast.LENGTH_SHORT).show();
} else {
txtResult.setBackgroundColor(0xFFFFEBEE);
txtResult.setTextColor(0xFFF44336);
txtResult.setText("❌ Errores:\n\n" + errors.toString());
Toast.makeText(this, "Corrige los errores", Toast.LENGTH_SHORT).show();
}
}
}🟩 7. Clase Validador Reutilizable
📄 FormValidator.java
import android.util.Patterns;
import com.google.android.material.textfield.TextInputLayout;
public class FormValidator {
public static boolean isEmpty(TextInputLayout layout, String error) {
String value = layout.getEditText().getText().toString().trim();
if (value.isEmpty()) {
layout.setError(error);
return true;
}
layout.setError(null);
return false;
}
public static boolean isValidEmail(TextInputLayout layout) {
String email = layout.getEditText().getText().toString().trim();
if (email.isEmpty()) {
layout.setError("El email es obligatorio");
return false;
}
if (!Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
layout.setError("Email inválido");
return false;
}
layout.setError(null);
return true;
}
public static boolean isValidPassword(TextInputLayout layout, int minLength) {
String password = layout.getEditText().getText().toString();
if (password.isEmpty()) {
layout.setError("La contraseña es obligatoria");
return false;
}
if (password.length() < minLength) {
layout.setError("MÃnimo " + minLength + " caracteres");
return false;
}
if (!password.matches(".*[A-Z].*")) {
layout.setError("Debe contener una mayúscula");
return false;
}
if (!password.matches(".*[0-9].*")) {
layout.setError("Debe contener un número");
return false;
}
layout.setError(null);
return true;
}
public static boolean isValidPhone(TextInputLayout layout, int minLength) {
String phone = layout.getEditText().getText().toString().trim();
if (phone.isEmpty()) {
layout.setError("El teléfono es obligatorio");
return false;
}
if (phone.length() < minLength) {
layout.setError("Teléfono muy corto");
return false;
}
layout.setError(null);
return true;
}
public static boolean isInRange(TextInputLayout layout, int min, int max) {
String valueStr = layout.getEditText().getText().toString().trim();
if (valueStr.isEmpty()) {
layout.setError("Este campo es obligatorio");
return false;
}
try {
int value = Integer.parseInt(valueStr);
if (value < min || value > max) {
layout.setError("Debe estar entre " + min + " y " + max);
return false;
}
} catch (NumberFormatException e) {
layout.setError("Valor inválido");
return false;
}
layout.setError(null);
return true;
}
}🟩 8. Uso del Validador
private boolean validateWithHelper() {
boolean isValid = true;
if (!FormValidator.isValidEmail(tilEmail)) isValid = false;
if (!FormValidator.isValidPassword(tilPassword, 6)) isValid = false;
if (!FormValidator.isValidPhone(tilPhone, 8)) isValid = false;
if (!FormValidator.isInRange(tilAge, 18, 100)) isValid = false;
return isValid;
}🟩 9. Patrones de Validación
// Email
Patterns.EMAIL_ADDRESS.matcher(email).matches()
// Teléfono
Patterns.PHONE.matcher(phone).matches()
// URL
Patterns.WEB_URL.matcher(url).matches()
// Solo letras
text.matches("[a-zA-Z]+")
// Solo números
text.matches("[0-9]+")
// Contraseña fuerte (8 chars, mayúscula, minúscula, número)
text.matches("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$")🟩 10. Propiedades de EditText
| Propiedad | Descripción |
|---|---|
android:inputType | Tipo de entrada |
android:hint | Texto de sugerencia |
android:maxLength | Longitud máxima |
android:minLines | LÃneas mÃnimas |
android:imeOptions | Opciones del teclado |
▶️ Cómo Ejecutar
- Abre Android Studio
- Presiona Run
- Completa el formulario y prueba las validaciones
🧪 Resultado Final
Formulario funcional con validaciones en tiempo real, mensajes de error claros y feedback visual.
📥 Descargar Proyecto
👉
🙌 Gracias por Visitar mi Blog
✔️ Compártelo
✔️ Déjame un comentario
✔️ SÃgueme para más contenido
❓ Preguntas Frecuentes
1. ¿Cuál es la diferencia entre EditText y TextInputLayout?
TextInputLayout es un contenedor de Material Design que envuelve EditText y agrega hints flotantes, contadores y mensajes de error mejorados.
2. ¿Cómo valido en tiempo real?
Usa TextWatcher con addTextChangedListener() en el EditText para validar mientras el usuario escribe.
3. ¿Cómo valido una contraseña segura?
Verifica longitud mÃnima, mayúsculas, minúsculas y números usando expresiones regulares.
4. ¿Validar en tiempo real o al enviar?
Combina ambos: validación ligera en tiempo real y completa al enviar.

No hay comentarios:
Publicar un comentario