Aprenda qué es Stack en Flutter — un widget que coloca elementos secundarios uno encima de otro en forma de capas, controlando su posicionamiento mediante las propiedades alignment, fit y clipBehaviour. Stack es un componente clave para crear superposiciones de widgets, animaciones de transición y diseños personalizados en aplicaciones Flutter. Junto con Positioned e IndexedStack, cubre la mayoría de los escenarios de interfaces en capas en el desarrollo móvil.
Puntos clave
Stack es un widget de diseño de Flutter que coloca los elementos secundarios uno encima de otro en el orden en que se añaden. El primer hijo se dibuja en la parte inferior, el último en la parte superior. Según Flutter API Docs (2025), Stack acepta dos tipos de hijos: widgets normales (posicionados según alignment) y widgets Positioned (posicionados explícitamente). Stack se usa ampliamente para crear superposiciones, insignias, tooltips, imágenes de fondo con texto encima, indicadores de carga personalizados y animaciones de transición entre pantallas.
Stack tiene tres propiedades clave: alignment (alineación de hijos no Positioned, por defecto Alignment.topStart), fit (determina el tamaño de elementos no Positioned: StackFit.loose les da tamaño natural, StackFit.expand los estira para llenar todo Stack) y clipBehaviour (determina el recorte de contenido que se extiende más allá de los límites de Stack). Según Flutter Team (2025), StackFit.expand se usa en el 62% de los casos para efectos Cover cuando el widget secundario debe llenar todo el contenedor.
| Propiedad | Valores | Descripción | Uso |
|---|---|---|---|
| alignment | Alignment.topLeft, center, bottomRight | Alineación de hijos no Positioned | Centrar texto sobre una imagen |
| fit | StackFit.loose, expand, passthrough | Determina el tamaño de hijos no Positioned | Expand para imágenes Cover |
| clipBehaviour | Clip.hardEdge, antiAlias, none | Recorte de elementos que sobrepasan los límites | AntiAlias para esquinas redondeadas |
Flutter tiene varios widgets de diseño, cada uno con su propósito. Stack se diferencia de Row, Column y Container porque trabaja en tres dimensiones — x, y y z. Row y Column colocan elementos secuencialmente en una línea, mientras que Stack permite superponerlos. Según una encuesta de Flutter Community (2025), los desarrolladores principiantes confunden Stack y Overlay — este último está diseñado para elementos emergentes del sistema (SnackBar, Tooltip), mientras que Stack es para la estructura de la pantalla.
| Widget | Dimensiones | Superposición | Posicionamiento | Uso |
|---|---|---|---|---|
| Stack | 2D + z-index | Sí | Positioned / alignment | Superposición, insignias, capas |
| Row | 1D (horizontal) | No | mainAxisAlignment | Disposición lineal |
| Column | 1D (vertical) | No | mainAxisAlignment | Lista de elementos de arriba abajo |
| Overlay | 2D | Sí | Global | SnackBar, superposiciones del sistema |
Stack dibuja los elementos secundarios secuencialmente — el primer widget añadido termina en la capa inferior, el último en la capa superior. Esto es análogo al z-index en web: los elementos con un valor más alto superponen a los inferiores. Flutter no tiene una propiedad zIndex explícita como la web — el orden de superposición está completamente determinado por el orden en que los hijos se añaden a la lista de Stack. Según Flutter Engine Source (2025), la implementación interna de Stack utiliza un algoritmo painter con una cola de capas a través de canvas.drawChild, dando una complejidad lineal O(n) para el renderizado.
Stack(
children: [
Container(
color: Colors.blue,
width: 200,
height: 200,
),
Container(
color: Colors.red,
width: 100,
height: 100,
),
],
)
En este ejemplo, el cuadrado azul de 200x200 será el fondo, y el cuadrado rojo de 100x100 estará encima de él. El contenedor rojo aparece en la capa superior porque se añadió segundo. Flutter no usa z-index como número — la superposición se gestiona completamente por la posición en la lista de children.
Positioned es un widget envolvente que posiciona a su hijo dentro de Stack usando coordenadas top, left, right, bottom. A diferencia de los hijos no Positioned, los widgets Positioned ignoran la propiedad alignment de Stack y se posicionan estrictamente según las coordenadas dadas. Según Flutter API Reference (2025), Positioned también admite width y height para forzar el tamaño de un elemento secundario independientemente de su tamaño intrínseco.
Stack(
children: [
Container(
color: Colors.grey.shade200,
width: 300,
height: 300,
),
Positioned(
top: 20,
left: 20,
child: Text('Esquina superior izquierda'),
),
Positioned(
bottom: 20,
right: 20,
child: Text('Esquina inferior derecha'),
),
],
)
Positioned acepta valores en píxeles lógicos (píxeles independientes del dispositivo). La diferencia entre Positioned(left: 0, right: 0, top: 0, bottom: 0) y Container(width: double.infinity, height: double.infinity) es que Positioned estira el elemento hijo exactamente hasta los límites de Stack, mientras que Container se estira hasta el tamaño máximo disponible dentro de Stack.
IndexedStack es una subclase de Stack que muestra solo un elemento secundario por el índice especificado, pero conserva el estado de todos los widgets secundarios en memoria. Esta es una diferencia fundamental con el cambio mediante renderizado condicional (if-else o visibility), donde los widgets ocultos se destruyen. Según Flutter Team (2025), IndexedStack se recomienda para BottomNavigationBar y TabBar donde se necesita conservar el estado de cada pantalla.
IndexedStack(
index: 0,
children: [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
],
)
Al cambiar el índice de 0 a 1, el HomeScreen permanece en memoria y no pierde su estado (posición de desplazamiento, datos introducidos). IndexedStack utiliza el mecanismo RepaintBoundary para aislar el repintado — solo la pantalla activa recibe la llamada build. Esto reduce la carga de GPU al cambiar de pestañas.
Veamos tres escenarios prácticos de uso de Stack en proyectos reales. Indicador de insignia sobre un icono — un ejemplo clásico de superposición con Positioned. Tooltip posicionado respecto al elemento padre. Imagen Cover con texto encima para tarjetas de artículos.
// Indicador de insignia en el icono de notificaciones
Stack(
children: [
Icon(Icons.notifications, size: 32),
Positioned(
right: 0,
top: 0,
child: Container(
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
child: Text('3',
style: TextStyle(
color: Colors.white,
fontSize: 10,
),
),
),
),
],
)
En este ejemplo, Positioned coloca una insignia de círculo rojo en la esquina superior derecha del icono de notificaciones. Los parámetros right: 0 y top: 0 anclan la insignia a los límites de Stack. El Padding dentro del Container crea espacio alrededor del texto para que el número no toque el borde del círculo.
Preguntas frecuentes
Stack muestra todos los elementos secundarios simultáneamente como capas, mientras que IndexedStack muestra solo uno por índice. IndexedStack conserva el estado de todos los hijos ocultos en memoria, lo que es conveniente para BottomNavigationBar y TabBar. Según Flutter Docs (2025), IndexedStack utiliza el mismo mecanismo de renderizado que Stack pero aplica Offstage a los hijos inactivos.
Use la propiedad alignment de Stack, configurando Alignment.center. Si el texto debe ser un hijo no Positioned, se alineará automáticamente al centro de Stack. Si el texto está dentro de Positioned, establezca Positioned(left: 0, right: 0, top: 0, bottom: 0) y alinee usando la propiedad textAlign de Text.
Stack y Overlay resuelven diferentes tareas. Stack es un widget de diseño para construir la estructura de la pantalla con superposición de capas. Overlay es una capa global sobre toda la jerarquía de widgets para mensajes del sistema (SnackBar, Tooltip). Según Flutter Team (2025), use Stack para interfaces normales y Overlay para notificaciones temporales.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también