Blog para desarrollo de aplicaciones en Android, aprende paso a paso como crear aplicaciones.

Usamos cookies propias y de terceros que entre otras cosas recogen datos sobre sus hábitos de navegación para mostrarle publicidad personalizada y realizar análisis de uso de nuestro sitio.
Si continúa navegando consideramos que acepta su uso. OK Más información | Y más

EditText y Validaciones de Formulario en Android

EditText y Validaciones de Formulario en Android

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

gradle
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

PropiedadDescripción
android:inputTypeTipo de entrada
android:hintTexto de sugerencia
android:maxLengthLongitud máxima
android:minLinesLíneas mínimas
android:imeOptionsOpciones del teclado

▶️ Cómo Ejecutar

  1. Abre Android Studio
  2. Presiona Run
  3. 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