TextField en Flutter

Domina la captura de entrada de usuario en tus aplicaciones

Descargar Ejemplos Completos

¿Qué es TextField?

El TextField es uno de los widgets más importantes en Flutter para capturar entrada de texto del usuario. Es esencial para formularios, búsquedas, login y cualquier interacción que requiera texto.

Características Principales:

  • ✅ Captura de texto simple y seguro
  • ✅ Validación y manejo de errores
  • ✅ Diferentes tipos de teclado
  • ✅ Decoración y personalización completa
  • ✅ Integración con Form y FormField

Sintaxis Básica

TextField Mínimo

TextField(
  onChanged: (text) {
    print('Texto cambiado: $text');
  },
)

TextField con Controlador

final TextEditingController _controller = TextEditingController();

TextField(
  controller: _controller,
  decoration: InputDecoration(
    labelText: 'Nombre',
    hintText: 'Escribe tu nombre',
    border: OutlineInputBorder(),
  ),
)

Propiedades Principales

controller

Controla el texto y estado del TextField

Tipo: TextEditingController

Requerido: No

decoration

Personaliza la apariencia del TextField

Tipo: InputDecoration

Requerido: No

onChanged

Función llamada cuando el texto cambia

Tipo: ValueChanged<String>

Requerido: No

keyboardType

Tipo de teclado a mostrar

Tipo: TextInputType

Por defecto: TextInputType.text

obscureText

Oculta el texto (para contraseñas)

Tipo: bool

Por defecto: false

maxLines

Número máximo de líneas

Tipo: int

Por defecto: 1

InputDecoration

La propiedad decoration permite personalizar completamente la apariencia del TextField.

labelText

Texto que aparece como etiqueta

hintText

Texto de sugerencia cuando está vacío

Escribe tu nombre

prefixIcon / suffixIcon

Iconos antes/después del texto

Texto

errorText

Texto de error cuando hay validación

Texto inválido
Este campo es requerido

Ejemplo Completo de Decoración:

TextField(
  decoration: InputDecoration(
    labelText: 'Correo electrónico',
    hintText: 'tu@email.com',
    prefixIcon: Icon(Icons.email),
    suffixIcon: Icon(Icons.check_circle, color: Colors.green),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
    focusedBorder: OutlineInputBorder(
      borderSide: BorderSide(color: Colors.blue, width: 2),
    ),
    errorText: _emailError,
    errorStyle: TextStyle(color: Colors.red),
  ),
)

Tipos de TextField

1. TextField Básico

TextField()

2. Con Borde Outline

border: OutlineInputBorder()

3. Con Icono

prefixIcon: Icon(Icons.search)

4. Para Contraseña

obscureText: true

5. Multilínea

maxLines: 5

6. Con Validación

Este campo es obligatorio
errorText: 'Campo requerido'

Manejo de Estado

1. TextEditingController

Para control avanzado del texto y estado

class _MyFormState extends State<MyForm> {
  final TextEditingController _controller = TextEditingController();
  
  @override
  void initState() {
    super.initState();
    _controller.addListener(_onTextChanged);
  }
  
  void _onTextChanged() {
    print('Texto actual: ${_controller.text}');
  }
  
  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      decoration: InputDecoration(labelText: 'Nombre'),
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

2. onChanged con setState

Para casos simples sin necesidad de controlador

class _MyFormState extends State<MyForm> {
  String _text = '';
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          onChanged: (text) {
            setState(() {
              _text = text;
            });
          },
          decoration: InputDecoration(labelText: 'Escribe algo'),
        ),
        Text('Has escrito: $_text'),
      ],
    );
  }
}

Tipos de Teclado

TextInputType.text

Teclado estándar para texto

ABC
keyboardType: TextInputType.text

TextInputType.emailAddress

Teclado optimizado para emails

@ .com
keyboardType: TextInputType.emailAddress

TextInputType.phone

Teclado numérico para teléfonos

123
keyboardType: TextInputType.phone

TextInputType.number

Teclado numérico estándar

123
keyboardType: TextInputType.number

TextInputType.multiline

Optimizado para texto multilínea

keyboardType: TextInputType.multiline

Personalizador de TextField

Texto actual:
// El código se generará aquí

Validación de Formularios

Validación con Form

Usando Form y TextFormField para validación integrada

final _formKey = GlobalKey<FormState>();

Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Por favor ingresa tu nombre';
          }
          return null;
        },
        decoration: InputDecoration(labelText: 'Nombre'),
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            // Formulario válido
          }
        },
        child: Text('Enviar'),
      ),
    ],
  ),
)

Validación Personalizada

Validaciones específicas para diferentes casos

String? _validateEmail(String? value) {
  if (value == null || value.isEmpty) {
    return 'El email es requerido';
  }
  if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
    return 'Ingresa un email válido';
  }
  return null;
}

TextFormField(
  validator: _validateEmail,
  decoration: InputDecoration(labelText: 'Email'),
)

Mejores Prácticas

✅ Lo que SÍ debes hacer

  • Usa TextEditingController para campos importantes
  • Implementa validación en todos los campos de formulario
  • Usa el keyboardType apropiado para cada campo
  • Proporciona hintText y labelText claros
  • Maneja el dispose de los controllers

❌ Lo que NO debes hacer

  • No olvides limpiar los controllers
  • No uses onChanged para validación en tiempo real compleja
  • No ignores la accesibilidad (semanticLabel)
  • No uses obscureText para campos que no son contraseñas
  • No olvides el manejo de errores

Tip Profesional

Para formularios complejos, considera usar packages como flutter_form_builder o reactive_forms que proporcionan validación más avanzada y manejo de estado.

Ejercicios para Practicar

Ejercicio 1: Formulario de Registro

Crea un formulario de registro con validación para nombre, email y contraseña.

Campos: Nombre (requerido), Email (validación), Contraseña (mínimo 6 caracteres)

Ejercicio 2: Búsqueda en Tiempo Real

Implementa un campo de búsqueda que filtre una lista mientras el usuario escribe.

Pista: Usa onChanged con debounce para optimizar

Ejercicio 3: Formulario de Contacto

Crea un formulario de contacto con campos para nombre, email, asunto y mensaje multilínea.

Campos: Usa TextFormField con validación personalizada

Solución de Problemas Comunes

❌ El texto no se actualiza

Solución: Asegúrate de llamar setState() o usar un controller

setState(() { _text = newValue; });

❌ Error con el controller

Solución: No olvides llamar dispose() en el controller

@override void dispose() { _controller.dispose(); super.dispose(); }

❌ El teclado no muestra @ para emails

Solución: Usa TextInputType.emailAddress

keyboardType: TextInputType.emailAddress