Ir al contenido

Guía de Flutter para novatos - Miguel Páramos

FAQ sobre Flutter pal que no tiene ni idea de Flutter | 2º DAM · PMDM

Interacción y botones sin necesitar StatefulWidget: SnackBars, funciones auxiliares y Diálogos Modales

Un error conceptual muy habitual en quien empieza con Flutter es creer que para que un botón o elemento interactivo ejecute acciones (como navegar, mostrar avisos, desencadenar peticiones o abrir modales), la pantalla tiene que ser forzosamente un StatefulWidget.

En realidad, un StatelessWidget es plenamente capaz de gestionar eventos de usuario e interactividad enriquecida sin necesidad de mutabilidad interna.

Ejemplo práctico: Las tres técnicas fundamentales

Sección titulada «Ejemplo práctico: Las tres técnicas fundamentales»

En el siguiente ejemplo funcional comprobamos cómo disparar SnackBars, delegar lógica a funciones auxiliares limpias y mostrar cuadros de diálogo modales (AlertDialog) desde un StatelessWidget:

import 'package:flutter/material.dart'; // Importa la librería base de componentes Material
class MiPantallaAcciones extends StatelessWidget { // Pantalla inmutable sin estado local
const MiPantallaAcciones({super.key}); // Constructor constante
void _boton4Pulsado(BuildContext context) { // Función auxiliar fuera del árbol para código limpio
debugPrint('Pulsado con lógica desacoplada'); // Registra evento en consola de depuración
ScaffoldMessenger.of(context).showSnackBar( // Solicita mostrar notificación al mensajero
const SnackBar(content: Text('¡Mensaje ejecutado desde función auxiliar!')), // Mensaje visual
); // Fin de showSnackBar
} // Fin de _boton4Pulsado
@override // Sobreescribe el método build
Widget build(BuildContext context) { // Retorna el árbol de la pantalla
return Scaffold( // Estructura visual básica de la pantalla
appBar: AppBar(title: const Text('Acciones en StatelessWidget')), // Barra superior con título
body: Center( // Centra el contenido en pantalla
child: Column( // Disposición vertical de widgets hijos
mainAxisAlignment: MainAxisAlignment.center, // Centra verticalmente los elementos
children: [ // Lista de widgets en la columna
ElevatedButton( // Botón 1: lanza un SnackBar
onPressed: () { // Callback al pulsar el botón
ScaffoldMessenger.of(context).showSnackBar( // Muestra la notificación inferior
const SnackBar( // Componente de notificación flotante
content: Text('Iniciando sesión...'), // Texto informativo
backgroundColor: Colors.teal, // Color de fondo personalizado
duration: Duration(seconds: 2), // Tiempo de permanencia en pantalla
), // Fin de SnackBar
); // Fin de showSnackBar
}, // Fin de onPressed
child: const Text('Mostrar SnackBar'), // Texto del botón
), // Fin de ElevatedButton
const SizedBox(height: 16), // Separación vertical de 16 píxeles
ElevatedButton( // Botón 2: delega en función auxiliar
onPressed: () => _boton4Pulsado(context), // Ejecuta función externa pasando context
child: const Text('Función Auxiliar'), // Texto del botón
), // Fin de ElevatedButton
const SizedBox(height: 16), // Separación vertical de 16 píxeles
ElevatedButton( // Botón 3: abre cuadro de diálogo modal
onPressed: () { // Callback al pulsar
showDialog( // Muestra diálogo modal en la capa superior
context: context, // Contexto para localizar el navegador
builder: (context) => AlertDialog( // Construye el cuadro de diálogo
title: const Text('Confirmación'), // Título del modal
content: const Text('¿Estás seguro de que deseas continuar?'), // Pregunta
actions: [ // Botones de decisión del modal
TextButton( // Opción cancelar
onPressed: () => Navigator.pop(context), // Cierra la ventana emergente
child: const Text('Cancelar'), // Etiqueta del botón
), // Fin de TextButton
FilledButton( // Opción confirmar con estilo destacado
onPressed: () { // Callback de confirmación
Navigator.pop(context); // Cierra la ventana modal
}, // Fin de onPressed
child: const Text('Aceptar'), // Etiqueta del botón de confirmación
), // Fin de FilledButton
], // Fin de lista de acciones
), // Fin de AlertDialog
); // Fin de showDialog
}, // Fin de onPressed
child: const Text('Abrir Diálogo de Confirmación'), // Texto del botón
), // Fin de ElevatedButton
], // Fin de lista children
), // Fin de Column
), // Fin de Center
); // Fin de Scaffold
} // Fin del método build
} // Fin de la clase MiPantallaAcciones