Widgets do Flutter que resolvem silenciosamente grandes problemas de interface (UI).
Quando você navega por tutoriais de Flutter, vê os mesmos widgets repetidamente: Container, Column, Row, ListView.
E tudo bem — todo mundo começa por aí. Mas, se você passar tempo suficiente mantendo apps reais, entregando funcionalidades sob pressão e corrigindo bugs de interface que só aparecem em um dispositivo específico e estranho, você começa a descobrir widgets que resolvem problemas silenciosamente antes mesmo que eles virem bugs.
Hoje, vamos falar sobre quatro widgets subestimados do Flutter que não recebem a atenção que merecem.
OverflowBar — Chega de Overflows.
Você já projetou um diálogo ou um bottom sheet com várias ações…
…e depois viu tudo quebrar em telas menores? Os botões transbordam (overflow). O texto quebra de um jeito estranho. Você adiciona um Wrap, ajusta o espaçamento e reza.
É exatamente por isso que o OverflowBar existe.
OverflowBar(
spacing: 12,
overflowSpacing: 8,
alignment: MainAxisAlignment.end,
children: [
TextButton(onPressed: () {}, child: const Text('Cancel')),
ElevatedButton(onPressed: () {}, child: const Text('Save')),
],
)
GridPaper — Depuração Visual de Layout
Se você já usou softwares de design ou edição de vídeo, provavelmente já ativou a grade (grid) para verificar se os elementos estão alinhados, com espaçamento uniforme e visualmente equilibrados. O GridPaper funciona da mesma maneira no Flutter. Ele sobrepõe uma grade na sua interface para que você possa ver instantaneamente o espaçamento, o alinhamento e o ritmo do layout — sem precisar adicionar bordas, cores ou recorrer a adivinhações. Em vez de “olhar no olho” para conferir os pixels, você começa a pensar em sistemas e consistência, que é exatamente como interfaces refinadas são construídas.

class DebugGridWrapper extends StatelessWidget {
final Widget child;
const DebugGridWrapper({super.key, required this.child});
@override
Widget build(BuildContext context) {
if (kDebugMode) {
return GridPaper(
color: Colors.red,
divisions: 2,
subdivisions: 4,
child: child,
);
}
return child;
}
}
No modo debug, este wrapper (envoltório) mostra a sobreposição do GridPaper para que você possa inspecionar o espaçamento e o alinhamento durante a construção. No modo release, ele desaparece silenciosamente, mantendo a interface de produção limpa. Eu uso esse wrapper especificamente para evitar enviar ferramentas de depuração para os usuários — porque sim, eu já enviei grades de layout para produção antes… e não, os usuários não ficaram impressionados. Não seja como eu.
TickerMode — Pause Animações Escondidas.
Animações são ótimas — até que continuem rodando quando ninguém pode vê-las. O TickerMode permite pausar todas as animações abaixo dele na árvore de widgets quando uma tela está inativa. Isso é especialmente útil para abas (tabs), páginas em offstage ou telas de fundo. Em vez de gerenciar manualmente cada animation controller, o TickerMode faz a coisa certa automaticamente — economizando bateria, CPU e poupando o seu “eu do futuro” de bugs de performance que só aparecem em produção.

import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: TickerModeSwitchExample(),
);
}
}
class TickerModeSwitchExample extends StatefulWidget {
const TickerModeSwitchExample({super.key});
@override
State<TickerModeSwitchExample> createState() =>
_TickerModeSwitchExampleState();
}
class _TickerModeSwitchExampleState extends State<TickerModeSwitchExample> {
bool _animationsEnabled = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('TickerMode (Correct Usage)')),
body: Column(
children: [
SwitchListTile(
title: const Text('Enable animations'),
subtitle: const Text('Controls TickerMode'),
value: _animationsEnabled,
onChanged: (value) {
setState(() => _animationsEnabled = value);
},
),
const Divider(),
Expanded(
child: Center(
child: TickerMode(
enabled: _animationsEnabled,
child: const RotatingIcon(),
),
),
),
],
),
);
}
}
class RotatingIcon extends StatefulWidget {
const RotatingIcon({super.key});
@override
State<RotatingIcon> createState() => _RotatingIconState();
}
class _RotatingIconState extends State<RotatingIcon>
with SingleTickerProviderStateMixin {
late final AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 2),
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: _controller,
child: const Icon(Icons.sync, size: 80),
);
}
}
Nota: Quando usei o TickerMode pela primeira vez, envolvi meu widget animado e alternei a flag enabled — mas a animação não parou. Depois de algum tempo depurando, aprendi o “pulo do gato”: o TickerMode só afeta animation controllers criados dentro de sua própria árvore de widgets. No exemplo, o controller do RotationTransition vive dentro do widget que está abaixo do TickerMode, então alternar a flag pausa e retoma a animação corretamente. Se o controller estivesse fora, ele continuaria rodando — provando que o posicionamento na árvore de widgets é crucial para o controle adequado.