Kodokon kodokon.com

Formularios: TextField, controladores y validación

Controla tus campos de entrada con TextEditingController y valida todas las entradas de una sola vez gracias a Form y TextFormField.

9 min · 3 preguntas

Abrir esta lección en Kodokon

Un campo de entrada sin controlador es una caja negra. TextEditingController te da el control: lee controller.text en cualquier momento, rellena el campo de antemano, límpialo después del envío o escucha cada pulsación de tecla con addListener. El controlador se crea en un State, nunca en build: de lo contrario, se recrearía en cada reconstrucción.

DART
import 'package:flutter/material.dart';

class NicknameField extends StatefulWidget {
  const NicknameField({super.key});

  @override
  State<NicknameField> createState() =>
      _NicknameFieldState();
}

class _NicknameFieldState extends State<NicknameField> {
  final _controller = TextEditingController();

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

  @override
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      decoration: const InputDecoration(
        labelText: 'Nickname',
        border: OutlineInputBorder(),
      ),
      onSubmitted: (value) => debugPrint(value),
    );
  }
}
El controlador vive en el State y muere en dispose().

En cuanto una pantalla tiene varios campos que comprobar, adopta el trío Form, GlobalKey<FormState> y TextFormField. Cada campo describe su regla en validator: la función devuelve un mensaje de error, o null si todo está bien. Una llamada a validate() sobre la clave dispara todos los validadores a la vez.

DART
import 'package:flutter/material.dart';

class SignUpForm extends StatefulWidget {
  const SignUpForm({super.key});

  @override
  State<SignUpForm> createState() => _SignUpFormState();
}

class _SignUpFormState extends State<SignUpForm> {
  final _formKey = GlobalKey<FormState>();
  final _emailController = TextEditingController();

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

  void _submit() {
    if (_formKey.currentState!.validate()) {
      debugPrint('Email: ${_emailController.text}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextFormField(
            controller: _emailController,
            keyboardType: TextInputType.emailAddress,
            decoration: const InputDecoration(
              labelText: 'Email',
            ),
            validator: (value) {
              if (value == null || value.isEmpty) {
                return 'Required field';
              }
              if (!value.contains('@')) {
                return 'Invalid address';
              }
              return null;
            },
          ),
          const SizedBox(height: 16),
          FilledButton(
            onPressed: _submit,
            child: const Text('Create account'),
          ),
        ],
      ),
    );
  }
}
validate() dispara todos los validadores del formulario.

Cuando se hace clic en el botón, validate() ejecuta cada validator: los mensajes devueltos aparecen en rojo bajo los campos correspondientes, y el método devuelve false si al menos un campo no es válido. Tu lógica de envío queda así detrás de un único if: es imposible enviar datos no válidos.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. ¿Para qué sirve un TextEditingController?
    • Para dibujar el borde del campo
    • Para leer y modificar el texto del campo, y escuchar sus cambios
    • Para validar automáticamente las direcciones de correo electrónico
    • Para cerrar el teclado
  2. ¿Qué debe devolver un validator cuando el valor es válido?
    • true
    • Una cadena vacía
    • null
    • El propio valor
  3. ¿Por qué llamar a _controller.dispose() en el método dispose() del State?
    • Para limpiar el campo en la pantalla
    • Para liberar recursos y evitar fugas de memoria
    • Para enviar el formulario