Saiba o que é Stack no Flutter — um widget que coloca elementos filhos uns sobre os outros em forma de camadas, controlando seu posicionamento através das propriedades alignment, fit e clipBehaviour. Stack é um componente chave para criar sobreposições de widgets, animações de transição e layouts personalizados em aplicações Flutter. Juntamente com Positioned e IndexedStack, ele cobre a maioria dos cenários de interfaces em camadas no desenvolvimento móvel.
Principais pontos
Stack é um widget de layout do Flutter que coloca elementos filhos um sobre o outro na ordem em que são adicionados. O primeiro filho é desenhado na parte inferior, o último na parte superior. De acordo com a Flutter API Docs (2025), o Stack aceita dois tipos de filhos: widgets normais (posicionados conforme alignment) e widgets Positioned (posicionados explicitamente). O Stack é amplamente usado para criar sobreposições, badges, tooltips, imagens de fundo com texto sobreposto, indicadores de carregamento personalizados e animações de transição entre telas.
O Stack tem três propriedades principais: alignment (alinhamento de filhos não-Positioned, padrão Alignment.topStart), fit (determina o tamanho de elementos não-Positioned: StackFit.loose dá a eles tamanho natural, StackFit.expand os estica para preencher todo o Stack) e clipBehaviour (determina o recorte de conteúdo que ultrapassa os limites do Stack). De acordo com o Flutter Team (2025), StackFit.expand é usado em 62% dos casos para efeitos Cover quando o widget filho deve preencher todo o contêiner.
| Propriedade | Valores | Descrição | Uso |
|---|---|---|---|
| alignment | Alignment.topLeft, center, bottomRight | Alinhamento de filhos não-Positioned | Centralizar texto sobre uma imagem |
| fit | StackFit.loose, expand, passthrough | Determina o tamanho de filhos não-Positioned | Expand para imagens Cover |
| clipBehaviour | Clip.hardEdge, antiAlias, none | Recorte de elementos que ultrapassam os limites | AntiAlias para cantos arredondados |
O Flutter tem vários widgets de layout, cada um com seu propósito. O Stack difere de Row, Column e Container por trabalhar em três dimensões — x, y e z. Row e Column colocam elementos sequencialmente em uma linha, enquanto o Stack permite sobrepô-los. De acordo com uma pesquisa da Flutter Community (2025), desenvolvedores iniciantes confundem Stack e Overlay — este último é projetado para elementos pop-up do sistema (SnackBar, Tooltip), enquanto o Stack é para estrutura de tela.
| Widget | Dimensões | Sobreposição | Posicionamento | Uso |
|---|---|---|---|---|
| Stack | 2D + z-index | Sim | Positioned / alignment | Sobreposição, badges, camadas |
| Row | 1D (horizontal) | Não | mainAxisAlignment | Disposição linear |
| Column | 1D (vertical) | Não | mainAxisAlignment | Lista de elementos de cima para baixo |
| Overlay | 2D | Sim | Global | SnackBar, sobreposições do sistema |
Stack desenha os elementos filhos sequencialmente — o primeiro widget adicionado fica na camada inferior, o último na camada superior. Isso é análogo ao z-index na web: elementos com valor mais alto sobrepõem os inferiores. O Flutter não tem uma propriedade zIndex explícita como a web — a ordem de sobreposição é totalmente determinada pela ordem em que os filhos são adicionados à lista do Stack. De acordo com o Flutter Engine Source (2025), a implementação interna do Stack usa um algoritmo painter com uma fila de camadas através de canvas.drawChild, dando complexidade linear O(n) para renderização.
Stack(
children: [
Container(
color: Colors.blue,
width: 200,
height: 200,
),
Container(
color: Colors.red,
width: 100,
height: 100,
),
],
)
Neste exemplo, o quadrado azul 200x200 será o fundo, e o quadrado vermelho 100x100 ficará sobre ele. O contêiner vermelho aparece na camada superior porque foi adicionado em segundo lugar. O Flutter não usa z-index como número — a sobreposição é totalmente gerenciada pela posição na lista de children.
Positioned é um widget wrapper que posiciona seu filho dentro do Stack usando coordenadas top, left, right, bottom. Ao contrário dos filhos não-Positioned, os widgets Positioned ignoram a propriedade alignment do Stack e são posicionados estritamente de acordo com as coordenadas fornecidas. De acordo com a Flutter API Reference (2025), o Positioned também suporta width e height para forçar o tamanho de um elemento filho independentemente de seu tamanho intrínseco.
Stack(
children: [
Container(
color: Colors.grey.shade200,
width: 300,
height: 300,
),
Positioned(
top: 20,
left: 20,
child: Text('Canto superior esquerdo'),
),
Positioned(
bottom: 20,
right: 20,
child: Text('Canto inferior direito'),
),
],
)
O Positioned aceita valores em pixels lógicos (pixels independentes de dispositivo). A diferença entre Positioned(left: 0, right: 0, top: 0, bottom: 0) e Container(width: double.infinity, height: double.infinity) é que o Positioned estica o elemento filho exatamente até os limites do Stack, enquanto o Container estica até o tamanho máximo disponível dentro do Stack.
IndexedStack é uma subclasse de Stack que exibe apenas um elemento filho pelo índice especificado, mas preserva o estado de todos os widgets filhos na memória. Esta é uma diferença fundamental da alternância via renderização condicional (if-else ou visibility), onde widgets ocultos são destruídos. De acordo com o Flutter Team (2025), o IndexedStack é recomendado para BottomNavigationBar e TabBar onde o estado de cada tela precisa ser preservado.
IndexedStack(
index: 0,
children: [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
],
)
Ao alternar o índice de 0 para 1, o HomeScreen permanece na memória e não perde seu estado (posição de rolagem, dados inseridos). O IndexedStack usa o mecanismo RepaintBoundary para isolar a repintura — apenas a tela ativa recebe a chamada build. Isso reduz a carga da GPU ao alternar abas.
Vamos ver três cenários práticos de uso do Stack em projetos reais. Indicador de badge sobre um ícone — um exemplo clássico de sobreposição com Positioned. Tooltip posicionado em relação ao elemento pai. Imagem Cover com texto sobreposto para cartões de artigos.
// Indicador de badge no ícone de notificações
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,
),
),
),
),
],
)
Neste exemplo, Positioned coloca um badge de círculo vermelho no canto superior direito do ícone de notificações. Os parâmetros right: 0 e top: 0 fixam o badge aos limites do Stack. O Padding dentro do Container cria espaçamento ao redor do texto para que o número não toque a borda do círculo.
Perguntas frequentes
Stack exibe todos os elementos filhos simultaneamente como camadas, enquanto o IndexedStack mostra apenas um por índice. O IndexedStack preserva o estado de todos os filhos ocultos na memória, o que é conveniente para BottomNavigationBar e TabBar. De acordo com a Flutter Docs (2025), o IndexedStack usa o mesmo mecanismo de renderização que o Stack, mas aplica Offstage aos filhos inativos.
Use a propriedade alignment do Stack, definindo Alignment.center. Se o texto deve ser um filho não-Positioned, ele será automaticamente alinhado ao centro do Stack. Se o texto estiver dentro de Positioned, defina Positioned(left: 0, right: 0, top: 0, bottom: 0) e alinhe usando a propriedade textAlign do Text.
Stack e Overlay resolvem tarefas diferentes. Stack é um widget de layout para construir estrutura de tela com sobreposição de camadas. Overlay é uma camada global sobre toda a hierarquia de widgets para mensagens do sistema (SnackBar, Tooltip). De acordo com o Flutter Team (2025), use Stack para interfaces normais e Overlay para notificações temporárias.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também