Flutter tornou-se um kit de ferramentas popular para a construção de aplicativos de plataforma cruzada. Suporta todas as principais plataformas, incluindo Android, iOS e a web.

A navegação é muito importante para qualquer aplicativo. Ele fornece uma abstração uniforme sobre APIs de navegação fornecidas por várias plataformas. O Flutter fornece dois tipos de APIs para navegação: imperativa e declarativa.

Neste tutorial, vamos cobrir a abordagem imperativa para navegação usada no Flutter 1.0, bem como a abordagem declarativa agora empregada no Flutter 2.0.

Veremos o seguinte:

Navegação imperativa (Flutter 1.0) Classe Flutter Navigator Rotas nomeadas Navegação declarativa ( Flutter 2.0) Flutter Navigator Usando RouterDelegate RouteInformationParser Juntando tudo

Navegação imperativa (Flutter 1.0)

O Flutter 1.0 adotou uma abordagem imperativa para a navegação .

No Flut Além disso, a navegação consiste em uma pilha de widgets em que os widgets são colocados na parte superior e exibidos na parte superior também.

Classe Flutter Navigator

O classe Navigator fornece todos os recursos de navegação em um aplicativo Flutter.

O Navigator fornece métodos para modifique a pilha empurrando para empilhar ou removendo-a da pilha. O método Navigator.push é para navegar para uma página mais recente e Navigator.pop é para voltar da página atual.

Aqui está um exemplo básico de pop e push: o método push leva BuildContext como o primeiro argumento e o segundo argumento é um PageBuilder. Este exemplo usa MaterialPageRoute, que fornece a animação de transição e lida com alterações de rota:

import’package: flutter/material.dart’; void main () {runApp (MaterialApp (title:’My App’, home: Main (),)); } class Main extends StatelessWidget {@override Widget build (BuildContext context) {return Scaffold (appBar: AppBar (title: Text (‘Main Route’),), body: Center (child: RaisedButton (child: Text (‘Open route’), onPressed: () {//empurrando SecondRoute Navigator.push (context, MaterialPageRoute (builder: (context)=> SecondRoute ()),);},),),); }}

O método pop usa apenas BuildContext e altera a rota atual.

class SecondRoute extends StatelessWidget {@override Widget build (BuildContext context) {return Scaffold (appBar: AppBar (title: Text (“Second Route”),), body: Center (child: RaisedButton (onPressed: () {//Removendo SecondRoute Navigator.pop (context);}, child: Text (‘Go back!’),),),); }}

O Navigator fornece mais métodos, incluindo * pushReplacement *, que tornam os argumentos semelhantes a push. Ele substituirá a rota atual, portanto, não é possível navegar de volta para a rota mais antiga.

Por exemplo, após o login bem-sucedido, você deseja usar * pushReplacement * para evitar que o usuário retorne à tela de login.

Rotas nomeadas

As rotas nomeadas permitem que você altere o caminho usando strings em vez de fornecer classes de componentes, o que, por sua vez, permite reutilizar o código.

Rotas nomeadas são definidas como um mapa no MaterialApp. Essas rotas podem ser usadas em qualquer parte do aplicativo.

Definindo rotas

A rota é um mapa com chaves de string e valores como construtores que são passados ​​para a propriedade routes em MaterialApp:

void main () {runApp (MaterialApp (title:’My App’, home: Main (),//Rotas definidas aqui rotas: {“second”:( context)=> SecondRoute ()},)) ; }

Usando rotas nomeadas

Em vez de push, pushNamed é usado para mudar para uma nova rota. Da mesma forma, * pushReplacementNamed * é usado em vez de pushReplacement. O método pop é o mesmo para todas as rotas.

class Main extends StatelessWidget {@override Widget build (BuildContext context) {return Scaffold (appBar: AppBar (title: Text (‘Main Route’),), body: Center (child: RaisedButton (child: Text (‘Open route’), onPressed: () {Navigator.pushReplacementNamed (context,”second”);},),),); }}

Navegação declarativa (Flutter 2.0)

O Flutter 2.0 vem com navegação renovada graças em grande parte ao seu suporte para um abordagem declarativa . Isso torna o roteamento uma função de estado-ou seja, as páginas mudam após a mudança de estado.

O Flutter 2.0 também tem um suporte melhor para navegação na web .

Este diagrama, compartilhado publicamente pela equipe do Flutter para anunciar Flutter Navigation 2.0 e Router , descreve o fluxo muito bem:

Flutter Navigator

O Navigator pega uma lista de páginas e exibe a última página. Você pode alterar suas páginas adicionando ou removendo páginas do final da lista.

O exemplo abaixo demonstra como usar a classe Navigator com o novo Flutter Navigator usando a navegação baseada em páginas.

O _page é gerenciado por estado por esta classe. Para navegação, esta _page é manipulada na chamada setState:

class _App extends State {//Criando estado para páginas List _pages=[];

A _page é passada para a classe Navigator. O Navigator mudará a página atual com base no valor de _page.

onPopPage é chamado quando a navegação baseada no sistema operacional é realizada, como pressionar o botão Voltar no Android, etc.

@override Widget build (Contexto BuildContext) {return MaterialApp (home: Navigator (onPopPage: (rota, resultado) {//verificar se a rota foi removida se (route.didPop (resultado)) {//remover a última página _pages.removeLast (); retornar verdadeiro ;} retornar falso;}, páginas: _pages,),); }}

A página inicial pode ser definida adicionando uma página no método de ciclo de vida initState:

@override void initState () {super.initState ();//configuração da página inicial _pages=[_ buildMain ()]; }

Para criar uma nova página de material, use o widget MaterialPage. MaterialPage leva um filho e uma chave. O Navigator usa a chave para diferenciar as páginas e detectar a alteração da página.

Ao clicar no botão, uma nova página é adicionada ao estado _page. setState é chamado para acionar uma reconstrução do widget e o Navigator lida automaticamente com a mudança de página.

//Esta função cria uma página usando MaterialPage Page _buildMain () {return MaterialPage (child: Scaffold (body: Center (child: ElevatedButton) (child: Text (“click”), onPressed: () {//Quando clicado, adiciona uma nova página a _page list _pages.add (_buildSecondPage ());//chama setState para acionar a reconstrução do widget setState (() {//criar uma cópia do array _pages=_pages.toList ();});},),),//Isso ajuda o Navigator a distinguir entre páginas diferentes), chave: ValueKey (“home”)); }

Esta página é construída da mesma forma que _buildMain, mas em vez de adicionar uma nova página, ele remove uma e inicia a reconstrução.

//Esta função executa a mesma tarefa que _buildMain Página _buildSecondPage () {return MaterialPage (child: Scaffold (body: Center (child: ElevatedButton (child: Text (“back”), onPressed: () {//Isso levará de volta ao main//remover a última página _pages.removeLast ();//chamar setState para acionar uma reconstrução setState (() {//criando uma cópia da lista _pages=_pages.toList ();});},),),), chave: ValueKey (“segundo”)); }

Além de usar a lista _pages como um estado, você pode usar qualquer outro estado para realizar a navegação. Aqui está outro exemplo:

class _App extends State {String _selected=”main”; Page _buildMain () {return MaterialPage (child: Scaffold (appBar: AppBar (), body: Center (child: ElevatedButton (child: Text (“click”), onPressed: () {setState (() {//adicionar um novo página _selected=”segundo”;});},),),), chave: ValueKey (“home”)); } Page _buildSecondPage () {return MaterialPage (child: Scaffold (appBar: AppBar (), body: Center (child: ElevatedButton (child: Text (“back”), onPressed: () {setState (() {//mudar de volta estado para principal _selected=”principal”;});},),),), chave: ValueKey (“segundo”)); } @override Widget build (BuildContext context) {return MaterialApp (home: Navigator (onPopPage: (route, result) {if (route.didPop (result)) {_selected=”main”; return true;} return false;}, páginas: [_buildMain (),//mostra apenas selecionar se o estado tiver o segundo selecionado if (_selected==”segundo”) _buildSecondPage ()],),); }}

Usando RouterDelegate

RouterDelegate é um widget central usado pelo Roteador. Ele responde à intenção do motor de push de rota e pop de rota. A nova navegação permite a criação de RouterDelegate para melhor controle da navegação.

Um RouterDelegate é criado estendendo a classe RouterDelegate com PopNavigatorRouterDelegateMixin, ChangeNotifier mixins.

_selecionado rastreia a rota atual. Isso é semelhante ao estado usado no exemplo anterior.

a classe AppRouter estende RouterDelegate com PopNavigatorRouterDelegateMixin, ChangeNotifier {String _selected=”main”;

Isso é usado pelo roteador para obter o estado mais recente do roteador e alterar a URL na barra de endereço.

//obter o estado correto do roteador @override AppRouteState get currentConfiguration=> AppRouteState (_selected);

A tecla de navegação é usada para oferecer suporte à navegação mais antiga.

//Isso para suporte à navegação mais antiga. final _navigation=GlobalKey (); @override GlobalKey get navigatorKey=> _navigation;

NoticeListeners é usado em vez de setState para acionar uma reconstrução. _selected é alterado para alterar a rota.

Page _buildMain () {return MaterialPage (child: Scaffold (appBar: AppBar (), body: Center (child: ElevatedButton (child: Text (“click”), onPressed: ( ) {_selected=”second”;//notificar mudanças de rota notificarListeners ();},),),), chave: ValueKey (“home”)); }

Isso é semelhante a _buildMain:

Page _buildSecondPage () {return MaterialPage (child: Scaffold (appBar: AppBar (), body: Center (child: ElevatedButton (child: Text (“back”), onPressed: () {_selected=”main”;//notificar mudanças de rota notificarListeners ();},),),), chave: ValueKey (“segundo”)); }

A função build retorna o widget Navigator, que é usado para criar o layout de outras páginas. Esta função é semelhante à construção da função anterior. Em vez de setState, notificaListeners é usado para acionar a reconstrução.

@override Widget build (BuildContext context) {return MaterialApp (home: Navigator (key: _navigation, onPopPage: (route, result) {if (! Route.didPop ( resultado)) {return false;} _selected=”main”;//notificar mudanças de rota notificarListeners (); return true;}, pages: [_buildMain (),//se a rota é a segunda mostra SecondPage if (_selected==”second”) _buildSecondPage ()],),); }

Esta função usa informações passadas pelo roteador para alterar a rota. Esta função é chamada para alterar a rota quando o mecanismo passa a intenção de push ou pop de rota. As informações passadas aqui são analisadas por uma classe diferente que discutiremos mais tarde.

@override Future setNewRoutePath (configuration) async {//página de atualização baseada em _selected=configuration.selected; }}

RouteInformationParser

setNewRoutePath recebe a configuração do roteador. Esta configuração é analisada por RouteInformationParser.

Para o estado de análise passado pelo sistema operacional, mecanismo, etc., uma classe deve estender RouteInformationParser. restoreRouteInformation obtém o valor de retorno de currentConfiguration e o converte em RouteInformation.

parseRouteInformation retorna o estado do roteador, que é passado para setNewRoutePath.

class AppRouteInformationParser extends RouteInformationParser {//Isso converte o estado de rota para rotear informações. @override RouteInformation restoreRouteInformation (configuration) {if (configuration.selected==”main”) {return RouteInformation (location:”/main”); } else {return RouteInformation (localização:”/segundo”); }}//Isso converte as informações da rota para o estado do roteador @override Future parseRouteInformation (RouteInformation routeInformation) async {var url=Uri.parse (routeInformation.location); imprimir (url.path); if (url.path==”/”) return AppRouteState (“main”); return AppRouteState (url.path.replaceAll (“/”,””)); }}

Juntando tudo

MaterialApp agora tem um construtor recém-nomeado, que implementa um roteador que recebe Delegate e InformationParser como argumentos.

class _App extends State {@override Widget build ( Contexto BuildContext) {return MaterialApp.router (routeInformationParser: AppRouteInformationParser (), routerDelegate: AppRouter ()); }}

Conclusão

Neste tutorial de navegação Flutter, explicamos como implementar a navegação em um aplicativo Flutter de acordo com a abordagem imperativa usada no Flutter 1.0 e a nova navegação declarativa introduzida com o Flutter 2.0.

Dependendo da natureza do seu projeto Flutter, qualquer tipo de navegação pode ser apropriado, mas também não é uma bala de lasca. Você deve sempre escolher a abordagem que melhor atende às suas necessidades, mesmo que isso signifique empregar uma combinação de ambas.

Para começar a navegar no Flutter, recomendo conferir Fluro e pacotes Voyager .