certmundo.
es‑mx

6 min de lectura

¿Qué son los widgets en Flutter y cómo se usan?

Un widget es el bloque básico de construcción en Flutter: todo lo que ves en la pantalla de una app es un widget.

Botones, textos, imágenes, columnas, filas — todos son widgets. Flutter construye la interfaz completa combinando widgets dentro de otros widgets.

¿Por qué todo es un widget?

En Flutter no existe separación entre "componentes visuales" y "componentes de lógica". Todo se modela como widget. Esta decisión hace que el código sea predecible y fácil de leer.

Cada widget describe cómo debe verse su parte de la interfaz. Cuando algo cambia, Flutter reconstruye solo los widgets necesarios.

Dos tipos fundamentales de widgets

Flutter divide los widgets en dos categorías principales: StatelessWidget y StatefulWidget.

StatelessWidget

Un StatelessWidget es un widget que no cambia después de ser creado.

Muestra información fija. No reacciona a eventos del usuario ni actualiza su contenido en pantalla.

Úsalo cuando la información que muestra no varía. Por ejemplo: un encabezado con el logo de Bimbo, una etiqueta de precio estático o un texto de bienvenida.

Estructura básica de un StatelessWidget:

class MiEncabezado extends StatelessWidget {
  const MiEncabezado({super.key});

  @override
  Widget build(BuildContext context) {
    return Text("Bienvenido a la app de Bimbo");
  }
}

El método build regresa el widget que se mostrará en pantalla. Flutter llama a build una sola vez para los widgets estáticos.

StatefulWidget

Un StatefulWidget es un widget que puede cambiar su apariencia en respuesta a eventos o datos.

Cuando el usuario presiona un botón, llena un formulario o se carga información de un servidor, usas StatefulWidget. Tiene un objeto State separado que guarda los datos cambiantes.

Estructura básica de un StatefulWidget:

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

  @override
  State<ContadorProductos> createState() => _ContadorProductosState();
}

class _ContadorProductosState extends State<ContadorProductos> {
  int cantidad = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("Productos en carrito: $cantidad"),
        ElevatedButton(
          onPressed: () {
            setState(() {
              cantidad++;
            });
          },
          child: Text("Agregar"),
        ),
      ],
    );
  }
}

El método setState() le avisa a Flutter que algo cambió. Flutter vuelve a llamar build y actualiza la pantalla.

Widgets de estructura: Column y Row

Para acomodar widgets en pantalla necesitas widgets de layout. Los más usados son Column y Row.

Widget Dirección Ejemplo de uso
Column Vertical (de arriba a abajo) Lista de productos
Row Horizontal (de izquierda a derecha) Íconos de una barra de navegación
Container Un solo hijo con estilo Caja con color de fondo
SizedBox Espacio vacío Separar dos elementos

Ejemplo con Column:

Column(
  children: [
    Text("Oferta del día — Liverpool"),
    Text("Televisor 55 pulgadas"),
    Text("Precio: $8,999"),
  ],
)

Cada elemento de la lista children es otro widget. Así se "anidan" widgets para construir la interfaz completa.

Ejemplo práctico: tarjeta de producto

Imagina que construyes una pantalla para la app de Mercado Libre México. Necesitas mostrar una tarjeta con nombre del producto, vendedor y precio.

class TarjetaProducto extends StatelessWidget {
  final String nombre;
  final String vendedor;
  final double precio;

  const TarjetaProducto({
    super.key,
    required this.nombre,
    required this.vendedor,
    required this.precio,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(12),
      margin: EdgeInsets.symmetric(vertical: 8),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(color: Colors.black12, blurRadius: 4),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            nombre,
            style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
          ),
          SizedBox(height: 4),
          Text("Vendedor: $vendedor"),
          SizedBox(height: 4),
          Text(
            "\$${precio.toStringAsFixed(0).replaceAllMapped(
              RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
              (m) => '${m[1]},',
            )}",
            style: TextStyle(color: Colors.green, fontSize: 18),
          ),
        ],
      ),
    );
  }
}

Este widget recibe tres parámetros nombrados (nombre, vendedor, precio). Como aprendiste en la lección anterior, Flutter usa intensamente los parámetros nombrados. El widget es Stateless porque la tarjeta solo muestra datos; no los modifica.

Cómo usarlo en pantalla:

TarjetaProducto(
  nombre: "Cafetera FEMSA Premium",
  vendedor: "TiendaFEMSA_Oficial",
  precio: 1299,
)

En pantalla, el texto del precio aparece como $1,299 en color verde, igual al formato que usan las apps comerciales mexicanas.

Ejemplo con StatefulWidget: contador de artículos

Ahora construye un widget que permite al usuario incrementar o decrementar la cantidad de un producto antes de agregarlo al carrito.

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

  @override
  State<SelectorCantidad> createState() => _SelectorCantidadState();
}

class _SelectorCantidadState extends State<SelectorCantidad> {
  int cantidad = 1;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        IconButton(
          icon: Icon(Icons.remove),
          onPressed: () {
            if (cantidad > 1) {
              setState(() {
                cantidad--;
              });
            }
          },
        ),
        Text(
          "$cantidad",
          style: TextStyle(fontSize: 20),
        ),
        IconButton(
          icon: Icon(Icons.add),
          onPressed: () {
            setState(() {
              cantidad++;
            });
          },
        ),
      ],
    );
  }
}

Cada vez que el usuario presiona + o -, setState actualiza cantidad y Flutter redibuja solo este widget. El resto de la pantalla no se toca.

Errores comunes

1. Olvidar setState en un StatefulWidget

Si cambias una variable sin llamar setState, la pantalla no se actualiza aunque el valor cambie en memoria.

// ❌ Incorrecto: la pantalla no cambia
onPressed: () {
  cantidad++;
}

// ✅ Correcto
onPressed: () {
  setState(() {
    cantidad++;
  });
}

2. Usar StatefulWidget cuando no es necesario

Muchos principiantes usan StatefulWidget para todo. Si el widget solo muestra texto fijo, usa StatelessWidget. El código queda más limpio y Flutter lo procesa más rápido.

3. No pasar const al constructor cuando es posible

Cuando un widget es completamente estático, declararlo con const mejora el rendimiento.

// ❌ Sin const
Text("Oferta del día")

// ✅ Con const
const Text("Oferta del día")

Flutter reutiliza el objeto en memoria en lugar de crearlo de nuevo en cada build.

4. Anidar Column dentro de Column sin límite de altura

Si pones un Column dentro de otro Column con hijos que se expanden, Flutter lanza un error de desbordamiento. Usa Expanded o Flexible para controlar el espacio disponible.

Widgets de contenido más usados

Widget Función
Text Muestra texto en pantalla
Image Muestra una imagen local o de red
Icon Muestra un ícono del paquete Material
ElevatedButton Botón con relieve, para acciones principales
TextField Campo de entrada de texto
Checkbox Casilla de selección
CircularProgressIndicator Indicador de carga

Estos widgets son los que más vas a combinar en tus primeras apps.

Resumen

Los widgets son la unidad mínima de Flutter. Cada pantalla es un árbol de widgets anidados. Elige StatelessWidget para contenido fijo y StatefulWidget cuando los datos cambian. Llama siempre setState para que Flutter sepa que debe redibujar. Con Column, Row y Container puedes construir la mayoría de las interfaces que necesitas en tus primeras apps.

Puntos clave

  • En Flutter, todo lo que aparece en pantalla es un widget: textos, botones, columnas, imágenes y hasta el espacio vacío.
  • Usa `StatelessWidget` para contenido fijo que no cambia; usa `StatefulWidget` cuando la interfaz debe reaccionar a eventos o datos nuevos.
  • El método `setState()` es obligatorio en un `StatefulWidget`: sin él, la pantalla no se actualiza aunque el valor de la variable cambie.
  • `Column` y `Row` son los widgets de layout más usados; te permiten apilar widgets vertical u horizontalmente para construir cualquier interfaz.
  • Declara tus widgets estáticos con `const` siempre que puedas: Flutter los reutiliza en memoria y tu app corre más rápido.

Comparte esta lección:

¿Qué son los widgets en Flutter y cómo se usan? | Flutter y Dart Básico: Crea tu primera app móvil | Certmundo