Una rejilla es una disposición de elementos en filas y columnas.
Hasta ahora, nuestras Apps han sido muy verticales. Todo fluía de arriba a abajo en una lista infinita. Pero, ¿y si queremos hacer una galería de fotos como la de Instagram? ¿O un panel de control con botones grandes?
Para eso necesitamos organizar el contenido en dos dimensiones. Necesitamos una Rejilla (Grid).
En Flutter, el widget encargado de esto es el GridView. Funciona de forma muy similar al ListView, pero añade un nivel de complejidad: tenemos que decidir cuántas columnas queremos y qué forma tendrán las celdas.
GridView.count: un número fijo de columnas
Si sabes exactamente cuántas columnas quieres (por ejemplo, “quiero 2 columnas fijas”), el constructor más sencillo es GridView.count.
Es perfecto para menús estáticos o galerías simples.
GridView.count(
crossAxisCount: 2, // Número de columnas (Eje cruzado)
mainAxisSpacing: 10, // Espacio vertical entre filas
crossAxisSpacing: 10, // Espacio horizontal entre columnas
padding: EdgeInsets.all(20), // Margen externo de la rejilla
children: [
Container(color: Colors.red, child: Center(child: Text("1"))),
Container(color: Colors.blue, child: Center(child: Text("2"))),
Container(color: Colors.green, child: Center(child: Text("3"))),
Container(color: Colors.orange, child: Center(child: Text("4"))),
],
)
Relación de aspecto
Por defecto, GridView intenta que las celdas sean cuadradas (relación 1:1). Pero a veces queremos tarjetas rectangulares (más anchas que altas, o viceversa).
Para controlar esto usamos la propiedad childAspectRatio.
- 1.0: Cuadrado perfecto.
- < 1.0: Más alto que ancho (Vertical, ej: 0.7 para pósters de cine).
- > 1.0: Más ancho que alto (Horizontal, ej: 1.5 para tarjetas de noticias).
GridView.count(
crossAxisCount: 2,
childAspectRatio: 1.5, // Celdas rectangulares apaisadas
children: [...],
)
GridView.extent: rejillas adaptables
El problema de GridView.count es que es rígido. Si pones crossAxisCount: 2, se verán 2 columnas en un móvil pequeño (quedando bien) y 2 columnas en una Tablet de 12 pulgadas (quedando unas celdas gigantescas y feas).
Para solucionar esto, usamos GridView.extent.
En lugar de decirle “cuántas columnas”, le decimos: “¿Cuál es el ancho MÁXIMO que puede tener cada celda?”. Flutter calculará cuántas caben automáticamente.
GridView.extent(
maxCrossAxisExtent: 150, // Cada celda medirá COMO MÁXIMO 150px de ancho
children: [...],
)
- En un móvil de 300px de ancho -> Caben 2 celdas.
- En una Tablet de 900px de ancho -> Caben 6 celdas.
Esta es la forma más sencilla de hacer tu diseño Responsive (adaptable) sin complicarte con cálculos de pantalla manuales.
GridView.builder: datos dinámicos
Al igual que con las listas, si vamos a mostrar 1.000 fotos descargadas de internet, no podemos usar los constructores normales. Necesitamos el renderizado perezoso (Lazy Loading).
Usaremos GridView.builder. Pero aquí la sintaxis se complica un poco, porque necesitamos un “Delegado” (gridDelegate) que controle la geometría.
El gridDelegate es el objeto que contiene la lógica matemática de cómo distribuir las baldosas.
GridView.builder(
itemCount: 100, // Tenemos 100 elementos
// Definimos la estructura de la rejilla aquí
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 3 Columnas fijas
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
// Construimos el item bajo demanda (igual que ListView)
itemBuilder: (context, index) {
return Container(
color: Colors.teal[100 * (index % 9)],
child: Center(child: Text('Item $index')),
);
},
)
Los dos delegados principales
El nombre de la clase es largo (SliverGridDelegateWith...), pero hay dos delegados que usaremos habitualmente:
SliverGridDelegateWithFixedCrossAxisCount: Equivalente a.count. Fijas el número de columnas.SliverGridDelegateWithMaxCrossAxisExtent: Equivalente a.extent. Fijas el ancho máximo del item para que sea responsivo.
Un consejo de diseño: SliverGrid
Aunque GridView es potente, a veces querrás mezclar una lista normal con una rejilla en la misma pantalla (por ejemplo, una cabecera, luego una rejilla de fotos y luego un pie de página).
Anidar un GridView desplazable dentro de un ListView suele provocar conflictos de restricciones y de scroll. Se puede resolver en casos pequeños con shrinkWrap y una física adecuada, pero para composiciones grandes es preferible compartir un único sistema de scroll.
Para esos casos avanzados se usan CustomScrollView y los slivers. Es un tema avanzado, pero conviene recordar el nombre: si necesitas combinar una cabecera, una lista y una rejilla bajo el mismo scroll, busca SliverList y SliverGrid.