Route é uma classe abstrata no Flutter que representa uma tela ou página separada no histórico de navegação do Navigator. As implementações concretas de Route — MaterialPageRoute, CupertinoPageRoute e PlatformRoute — determinam como a tela é exibida e qual animação é usada durante a transição. Ao contrário de um widget comum, Route tem seu próprio ciclo de vida com os métodos didPush, didPop, didReplace e didChangeNext. De acordo com a Flutter API Reference (2026), cada Route gerencia ModalBarrier, leva em conta características específicas da plataforma (deslizar para trás no iOS) e garante o isolamento de estado entre telas.
Pontos principais
Route é a base do sistema de navegação do Flutter. Cada tela que o usuário vê em um aplicativo é representada por um objeto Route localizado na pilha do Navigator. Route abstrai a tela do código de controle: Navigator adiciona e remove Route, enquanto dentro de Route está a interface que o usuário vê. Esta arquitetura separa a responsabilidade entre navegação e exibição.
Ao contrário da simples substituição de widgets, Route fornece serviços indisponíveis para widgets comuns: ModalBarrier (escurecimento do fundo quando um diálogo está aberto), controle de animação de entrada e saída, manipulação do botão físico de voltar no Android e integração com animação Hero para transições suaves entre telas.
De acordo com Flutter Cookbook (2026), Route é um elemento chave para animação Hero: um widget Hero em uma Route anima automaticamente a transição para um widget Hero na próxima Route, criando um efeito de elemento “voando”. Isso é possível precisamente porque Route mantém ambas as telas no Overlay durante a animação.
Route é a base tanto para aplicativos móveis simples (através do Navigator 1.0) quanto para cenários complexos com links profundos (Navigator 2.0). No Navigator 2.0, Route representa uma Page que o RouterDelegate converte a partir da configuração de rota. Portanto, entender Route é essencial para trabalhar com qualquer sistema de navegação do Flutter — independentemente da abordagem ou pacote escolhido.
Flutter fornece várias implementações embutidas de Route, cada uma adaptando o comportamento a uma plataforma específica. Escolher o tipo correto de Route afeta a experiência do usuário: animação Material no Android e animação Cupertino no iOS criam a sensação de um aplicativo “nativo”.
| Tipo de Route | Animação | Plataforma | Características |
|---|---|---|---|
| MaterialPageRoute | Deslizar de baixo para cima | Android, desktop | Sombra na transição, manipulação automática de SafeArea |
| CupertinoPageRoute | Deslizar da direita para esquerda | iOS, iPadOS | Gesto de deslizar para trás, fundo transparente durante a transição |
| PlatformRoute | Seleção automática | Todas as plataformas | Seleciona o tipo com base no TargetPlatform |
| PageRouteBuilder | Personalizada | Todas as plataformas | Controle total sobre a animação através de AnimationController |
MaterialPageRoute é a implementação de Route mais usada. Ela anima a nova tela entrando de baixo para cima com aparecimento gradual. Ao sair, a tela anima de cima para baixo, retornando à sua posição original. A barra de ferramentas (AppBar) e o corpo da tela animam separadamente, criando um efeito de hierarquia.
CupertinoPageRoute imita o UINavigationController do iOS. A nova tela entra pela direita, cobrindo a anterior. A característica chave é o suporte ao gesto interativo de deslizar para trás, implementado através de CupertinoBackGestureDetector. Este gesto é manipulado mesmo durante a animação, proporcionando um comportamento natural familiar aos usuários de iPhone.
Route tem seu próprio ciclo de vida, que difere do ciclo de vida de um StatefulWidget comum. Compreender este ciclo é necessário para a inicialização adequada de dados, inscrições em streams e liberação de recursos ao fechar uma tela.
O ciclo de vida da Route consiste em quatro estágios principais. Transição — Route é criada e animada na entrada (didPush é chamado). Ativo — Route é totalmente exibida e interage com o usuário. Inativo — outra Route cobre a atual (diálogo, folha inferior), mas a Route permanece na pilha. Descartado — Route é removida da pilha e destruída, didPop e dispose são chamados.
Os métodos do ciclo de vida de Route podem ser sobrescritos em uma implementação personalizada. Por exemplo, didPop é chamado quando Route é removida da pilha — aqui você pode salvar dados de rascunho. didChangeNext é chamado quando a próxima Route na pilha mudou — útil para atualizar a UI quando o histórico de navegação muda.
De acordo com Flutter API Route.didPop (2026), é importante não confundir o ciclo de vida da Route com o ciclo de vida do State dentro da Route. StatefulWidget dentro de Route tem seu próprio initState e dispose, que são chamados durante os estágios de Transição e Descartado respectivamente. Route vive mais que seu State interno — Route permanece no Overlay mesmo quando seus widgets estão temporariamente ocultos por outra Route.
Route fornece mecanismos para passar dados tanto na entrada (quando criada) quanto na saída (quando concluída). A passagem adequada de dados via Route elimina a necessidade de variáveis globais e InheritedWidget, tornando a navegação type-safe e previsível.
Para passar dados para uma nova tela, use o construtor do widget receptor ou o parâmetro arguments no Navigator.pushNamed. Dentro de Route, os dados são acessíveis através de RouteSettings.arguments, que é armazenado no objeto Route. Esta abordagem funciona para todos os tipos de Route — MaterialPageRoute, CupertinoPageRoute e implementações personalizadas.
Para retornar dados, use o segundo argumento de Navigator.pop(context, result). Navigator.push retorna Future
Ao chamar Navigator.push diretamente com MaterialPageRoute, os dados são passados através do construtor da tela de destino. MethodChannel não é usado — esta é uma interação pura de Dart. Esta abordagem é preferível para passagem type-safe de objetos complexos.
Vamos ver um exemplo de criação de um Route personalizado com sua própria animação e passagem de dados. PageRouteBuilder permite definir animações de entrada e saída com controle total sobre a curva de animação e duração.
// Route personalizado com animação de deslizamento
Navigator.push(context, PageRouteBuilder(
pageBuilder: (context, animation, secondaryAnimation) {
return DetailPage(productId: '42');
},
transitionsBuilder: (context, animation, secondaryAnimation, child) {
const begin = Offset(0.0, 0.3);
const end = Offset.zero;
final tween = Tween(begin: begin, end: end);
final offsetAnimation = animation.drive(tween);
return SlideTransition(position: offsetAnimation, child: child);
},
transitionDuration: const Duration(milliseconds: 400),
));
// Retornar dados da tela
ElevatedButton(
onPressed: () => Navigator.of(context).pop({'selected': true, 'id': '42'}),
child: const Text('Selecionar'),
);
// Obter resultado na tela de chamada
final result = await Navigator.push(context, MaterialPageRoute(
builder: (context) => const SelectionPage(),
));
if (result != null) {
print('Selecionado: ${result['selected']}');
}
No exemplo, PageRouteBuilder define uma animação personalizada de deslizamento de baixo com transparência. transitionDuration define a velocidade da animação. O código também demonstra a passagem de resultado: a tela de detalhe retorna um Map com a seleção do usuário, e a tela de chamada recebe estes dados através do Future do push. Route garante isolamento completo: rascunhos na tela de detalhe não afetam o estado da lista.
Perguntas frequentes
Route é um objeto que gerencia uma tela no nível de navegação: armazena animação, ModalBarrier e ciclo de vida. Widget é uma descrição de uma parte da interface. Route contém Widget dentro de si, mas também fornece serviços (camada Overlay, animação Hero) indisponíveis para widgets comuns. Uma Route pode conter uma hierarquia complexa de widgets de qualquer profundidade.
Use PageRouteBuilder com os parâmetros pageBuilder (construção da tela) e transitionsBuilder (definição da animação). Em transitionsBuilder, estão disponíveis animation (0.0–1.0) e secondaryAnimation para animações paralelas. Para controle total, crie uma subclasse de Route e sobrescreva buildPage, createAnimationController e buildTransitions, dando acesso a AnimationController de baixo nível.
Para passar objetos complexos, use o construtor da tela de destino ao chamar Navigator.push diretamente ou o parâmetro arguments com pushNamed. Certifique-se de que o objeto seja serializável (Map, JSON ou classe personalizada). Para passagem type-safe no Flutter, use modelos freezed ou json_serializable, que garantem desserialização correta ao passar via RouteSettings.
Route.dispose não é chamado se Route permanecer na pilha do Navigator. Por exemplo, ao abrir uma nova Route, a Route antiga vai para o estado inativo mas não é destruída — permanece na pilha para retorno rápido. Dispose é chamado apenas quando Route é removida da pilha via pop, pushReplacement ou pushAndRemoveUntil. Para liberar recursos, use o dispose do State dentro de Route, não o dispose da própria Route.
Use ModalRoute.of(context) para obter a Route atual do BuildContext. A propriedade ModalRoute.isActive mostra se a Route é a tela atualmente visível. ModalRoute.isCurrent — true se a Route é o topo da pilha. Para observar mudanças na pilha, inscreva-se nos observadores do Navigator através de RouteAware e RouteObserver, que notificam sobre mudanças de Route ativa.
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