Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Flutter: Arquitetura e Navegação

Flutter: Arquitetura e Navegação

Entendendo navegação - Apresentação

Apresentando o curso e o instrutor

Olá! Gostaríamos de dar as boas-vindas a mais um curso de Flutter aqui na Alura. Meu nome é William Bezerra.

Audiodescrição: William é um homem pardo, com cabelo e barba pretos, que está utilizando óculos.

Irei acompanhar vocês ao longo desta jornada, na qual construiremos o aplicativo Focus. Este aplicativo auxilia os usuários a gerirem o tempo enquanto executam atividades, estudam ou realizam suas tarefas.

Descrevendo o aplicativo Focus

O aplicativo consiste em duas telas principais. A tela inicial apresenta os diferentes modos: modo foco, pausa curta e pausa longa. Cada modo redireciona para a mesma tela, mas com seu contexto específico. No modo foco, temos a tela de cronômetro, onde é possível gerenciar o tempo de forma mais extensa, permitindo ao usuário interagir, por exemplo, iniciando o cronômetro do modo foco, pausando, parando e trazendo toda essa interação. Podemos pausar, continuar, reiniciar, enfim, proporcionando uma estrutura muito interessante. Os demais modos funcionam de maneira semelhante, mas com tempos um pouco menores.

Explorando conceitos e técnicas do curso

Ao longo da construção deste projeto, abordaremos diferentes contextos e conceitos, aplicando muitos elementos do mercado e aprofundando bastante. Começaremos com a navegação, inicialmente trabalhando com a navegação mais simples, utilizando o push com o MaterialPageRoute. Em seguida, aprofundaremos mais, trabalhando com rotas nomeadas, passagem de parâmetros entre telas e passagem de parâmetros voltando entre telas, possibilitando a construção de um aplicativo escalável, com uma navegação mais estruturada.

Além da navegação, trabalharemos também conceitos de estado, para garantir que as interações dos usuários sejam performáticas e funcionem de maneira eficiente. Inicialmente, começaremos com o setState, um conceito mais geral do Flutter. Posteriormente, aprofundaremos com o ValueNotifier e o ChangeNotifier, conceitos que possibilitam trabalhar com performance e melhorar a qualidade dos projetos. Por fim, estruturaremos toda a lógica de gerenciamento de estado do aplicativo com uma arquitetura MVVM, que também possibilita a construção de aplicativos escaláveis.

Convidando à participação e engajamento

Este curso é destinado a quem já entende um pouco de Flutter, consegue construir uma tela, mas está começando e deseja se aprofundar ainda mais, trabalhando com navegação e gerenciamento de estado. Esperamos que estejam empolgados, pois nós estamos. Se já estão começando, convidamos a engajar, compartilhar o curso na comunidade e chamar amigos. Nos vemos na próxima aula.

Entendendo navegação - Navegando entre páginas

Introduzindo o aplicativo Focus

Você foi contratado para dar continuidade ao aplicativo Focus, um aplicativo de gestão de tempo que auxilia seus usuários a focarem em um determinado período para estudar, realizar tarefas e também descansar. O aplicativo é dividido em três grandes funcionalidades: o modo foco, que representa o período de tempo em que nos concentramos em algo para realizar uma tarefa, estudar ou executar alguma atividade; e os modos de pausa, que podem ser uma pausa curta, de 5 ou 10 minutos, ou uma pausa longa, para descansar por um período maior.

Ao assumir o aplicativo e navegar por ele, percebemos que não conseguimos acessar o modo foco, a pausa curta ou a pausa longa na página inicial, apesar de o time ter informado que a estrutura já estava pronta, incluindo a parte de widget e a tela. Vamos abrir o código no VS Code e observar que, dentro da arquitetura do aplicativo, temos um aplicativo aberto com duas páginas: a home page e a time page.

Explorando a estrutura do aplicativo

Na home page, a estrutura inclui um scaffold, uma safe area, um padding, uma coluna, imagens e três botões: o botão do modo foco, o botão da pausa curta e o botão da pausa longa. No entanto, os eventos de clique (onPressed) desses botões estão nulos, com apenas um comentário indicando uma tarefa a ser implementada para a pausa longa e a pausa curta. Apesar disso, já temos a time page.

Para garantir que a time page também está funcionando, vamos abrir o aplicativo para entender a configuração atual e por que ainda não conseguimos configurar a navegação. Ao abrir o aplicativo, vemos a estrutura inicial, que inclui o material app, o título, informações de data, o tema e a home, que é a home page. Se substituirmos a home page pela time page, conseguimos definir o tipo de tempo, como timeType.focus, e passar para a time page. Ao recarregar o aplicativo, veremos como essa página está estruturada.

Configurando a navegação entre páginas

Para isso, podemos começar com a seguinte configuração:

home: const TimerPage()

O ponto importante é que temos duas telas, mas elas ainda não se comunicam. Não conseguimos abrir a home e chamar a time page porque não configuramos a navegação entre os botões. Precisamos implementar essa navegação para que funcione corretamente dentro do aplicativo.

Para definir o tipo de tempo, podemos especificar o timerType na TimerPage:

home: const TimerPage(timerType: TimerType.focus),

Ao carregar o aplicativo, verificamos que o modo foco está funcionando. Se trocarmos o modo foco pelo modo pausa longa, veremos a pausa longa, e se trocarmos para uma pausa curta, também teremos a pausa curta. As duas telas estão visualmente bem estruturadas, mas agora precisamos estabelecer a comunicação entre elas.

Implementando a navegação com o Navigator

Para implementar a navegação no Flutter, utilizamos o Navigator, que é uma função padrão encontrada na maioria dos aplicativos. Com ele, conseguimos navegar entre diferentes páginas. Por exemplo, se estivermos na página inicial e quisermos ir para o modo foco, pausa curta ou pausa longa, precisamos implementar essa funcionalidade inicialmente.

Vamos utilizar o Navigator, que é a configuração padrão do Flutter para navegação. Ao abrir a página inicial, vamos direto ao botão de modo foco e implementar essa navegação. Quando clicarmos no botão modo foco, a tela correspondente será aberta. Para isso, utilizamos o Navigator, que é a configuração padrão do Flutter para navegação.

Primeiro, vamos adicionar a ação de clique ao botão do modo foco:

onPressed: () {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => TimerPage(timerType: TimerType.focus),
        ),
    );
},

Adicionando navegação para pausas curtas e longas

Temos uma classe chamada Navigator, e ao chamar o método push, conseguimos construir a próxima página. O método push requer dois parâmetros: o context, que é o contexto da página, e a rota. A navegação precisa ocorrer dentro de um contexto, pois é necessário saber em qual página estamos para direcionar à próxima.

Além do contexto, precisamos definir a rota. Podemos utilizar o MaterialPageRoute, que é a estrutura do MaterialApp para construir uma rota específica. Dentro do builder, temos uma função BuildContext que retorna um widget, estruturando a próxima rota. Substituímos o builder por um context que retorna o componente desejado na próxima tela, que no nosso caso é a TimerPage com o TimerType definido como Focus.

Após salvar e adicionar a vírgula após Focus para correta indentação, temos uma estrutura de navegação para a TimerPage, passando o tipo TimerFocus. Ao abrir o aplicativo e clicar no modo Foco, seremos redirecionados para a página correspondente. Se implementarmos o mesmo para as outras duas chamadas, mudando o tipo, conseguiremos navegar entre elas.

Para a pausa curta, copiamos e colamos o mesmo método, alterando o tipo de Timer. Como é a mesma página, é simples:

onPressed: () {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => TimerPage(timerType: TimerType.shortBreak),
        ),
    );
},

Para o último botão, repetimos o processo, substituindo o TimerType por Long Break:

onPressed: () {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) => TimerPage(timerType: TimerType.longBreak),
        ),
    );
},

Testando a navegação implementada

Agora, podemos testar: ao clicar em pausa curta, a página correspondente é chamada, e o mesmo ocorre para a pausa longa.

Conseguimos estruturar nossa primeira chamada entre páginas do aplicativo. Um ponto importante a destacar é que, ao chamar uma nova rota, podemos voltar para a tela anterior utilizando o botão do emulador. Esse método será explorado na próxima etapa.

Entendendo navegação - Retornando dados entre páginas

Discutindo a funcionalidade de navegação entre telas

Nós já implementamos a navegação entre as telas do nosso aplicativo. Agora, conseguimos abrir o modo foco, o modo pausa curta e o modo pausa longa. Entretanto, um ponto importante que precisamos discutir é a funcionalidade de voltar para a tela anterior após abrir uma nova tela. Por que isso funciona? Essa é uma característica essencial da navegação, que permite ir para uma rota e retornar à página anterior.

O método que utilizamos para isso é chamado de pop. Ele é um método nativo que podemos implementar diretamente. Basicamente, o pop é acionado quando realizamos alguma ação no dispositivo, como apertar o botão de voltar, que nos leva à tela anterior. Também podemos chamar esse método diretamente no código usando navigator.pop, o que destrói a tela atual e retorna à anterior.

Implementando o método pop no modo foco

Por exemplo, no modo foco, ao invés de iniciar uma ação, podemos configurar para voltar à tela anterior. Vamos fazer isso. Dentro de timerPaging, temos o componente TimerWidget, que possui um botão de iniciar com uma ação vazia. Vamos configurar esse botão para executar navigator.pop, salvando a alteração. Agora, ao apertar iniciar, ele destruirá a tela atual e retornará à anterior.

Para implementar isso, podemos usar o seguinte código:

onPressed: () {
  Navigator.pop(context);
},

Retornando valores com o método pop

Além disso, podemos fazer interações mais complexas. Por exemplo, ao chamar a tela do modo foco, podemos querer saber se a tarefa foi concluída e ser notificados na tela anterior ao retornar. Isso é possível com o pop, pois ele pode receber um parâmetro terResult, que é um retorno para a aplicação anterior. Podemos, por exemplo, informar o tempo que o usuário permaneceu na tela anterior, como 10 minutos.

Para retornar com um valor, podemos modificar o código para:

onPressed: () {
  Navigator.pop(context, '10 min');
},

Recebendo dados de retorno na HomePage

Na HomePage, onde construímos a interação da rota, podemos receber esse dado de volta. Assim, quando chamamos a página, ela realiza suas funções e retorna com um dado. Podemos usar finalResult = navigate.push e precisamos fazer um await, pois o resultado não é imediato. A função deve ser transformada em assíncrona, adicionando async ao proced. Quando a função retornar, teremos o resultado, que pode ser tipado como uma string, podendo também ser nula.

Primeiro, configuramos a chamada da nova página:

final result = Navigator.push(

Como precisamos aguardar o resultado, transformamos a função em assíncrona:

final result = await Navigator.push(

E então, integramos isso ao botão:

onPressed: () async {
  final result = await Navigator.push(

Verificando e exibindo o resultado retornado

Para garantir que o resultado seja uma string ou nulo, ajustamos o tipo:

final result = await Navigator.push<String?>(

Ele pode não nos retornar nada. Com esse resultado, podemos verificar, por exemplo, se o resultado é diferente de nulo e, se for, podemos mostrar um dialog. Vamos ter aqui a função de builder, alertDialog, e vamos colocar o título como parâmetro, que será um texto para mostrar, por exemplo, o resultado.

Primeiro, verificamos se o resultado não é nulo:

if (result != null) {
  
}

E então, mostramos o diálogo com o resultado:

if (result != null) {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: Text(result),
    ),
  );
}

Corrigindo a implementação e explicando a estrutura de navegação

Com isso, temos uma interação específica para o modo foco. Ao iniciar o modo foco, a função está esperando essa página voltar. Quando clicamos em iniciar, ele apenas retorna e leva o dado para a tela anterior. Ao voltar, ele deveria mostrar o dado para nós. Por que não mostrou? Vamos verificar. Chamamos aqui o modo foco, iniciamos, voltamos. É porque estávamos olhando para o botão errado. Na verdade, implementamos no pausa curta. Nesse caso, funcionará para o pausa curta e não para o modo foco. No pausa curta, ao clicar em iniciar, ele volta para a tela anterior e agora sim, caiu no botão. Temos aqui o resultado, com os 10 minutos que configuramos, e ao verificar, ele mostrará no aplicativo o tempo que a pessoa usuária ficou.

Com isso, conseguimos ter interação entre a tela anterior e a nova tela. Isso só acontece porque o Flutter trabalha com a estrutura de navegação chamada de Navigator Stack. Funciona literalmente como uma pilha de pratos. Imagine o seguinte: temos a mesa da sala de jantar e adicionamos o primeiro prato, que representa a Home. Em seguida, adicionamos o segundo prato, que é a Time Page, e assim por diante, empilhando pratos e montando uma pilha de rotas, uma pilha de páginas.

Essa estrutura de navegação é eficiente porque, ao retirar o prato que está em cima, podemos avisar ao prato que está embaixo sobre algo. Por exemplo, ao tirar o prato de cima, podemos colocar uma toalha sobre o prato de baixo. Essa é a interação que ocorre na navegação dentro do Flutter, seguindo a estrutura de Navigator Stack e utilizando o padrão LIFO (Last In, First Out). Ou seja, o último prato a entrar será o primeiro a sair.

Com essa lógica, podemos, por exemplo, remover três pratos de uma pilha de cinco ou seis pratos até chegar ao prato azul. Essa lógica é aplicada na navegação com Flutter. A navegação funciona como uma pilha, com uma rota sobre a outra, permitindo navegar dentro dessa estrutura, sendo a última a entrar e a primeira a sair, seguindo o padrão LIFO.

Até agora, conseguimos estruturar bem essa navegação e, na próxima etapa, veremos ainda mais sobre esse tema.

Sobre o curso Flutter: Arquitetura e Navegação

O curso Flutter: Arquitetura e Navegação possui 95 minutos de vídeos, em um total de 26 atividades. Gostou? Conheça nossos outros cursos de Flutter em Mobile, ou leia nossos artigos de Mobile.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Escolha a duração do seu plano

Conheça os Planos para Empresas