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.
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.
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.
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.
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
.
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.
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.
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),
),
);
},
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),
),
);
},
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.
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.
pop
no modo focoPor 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);
},
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');
},
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(
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),
),
);
}
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.
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:
Impulsione a sua carreira com os melhores cursos e faça parte da maior comunidade tech.
1 ano de Alura
Assine o PLUS e garanta:
Mobile, Programação, Front-end, DevOps, UX & Design, Marketing Digital, Data Science, Inovação & Gestão, Inteligência Artificial
Formações com mais de 1500 cursos atualizados e novos lançamentos semanais, em Programação, Inteligência Artificial, Front-end, UX & Design, Data Science, Mobile, DevOps e Inovação & Gestão.
A cada curso ou formação concluído, um novo certificado para turbinar seu currículo e LinkedIn.
No Discord, você participa de eventos exclusivos, pode tirar dúvidas em estudos colaborativos e ainda conta com mentorias em grupo com especialistas de diversas áreas.
Faça parte da maior comunidade Dev do país e crie conexões com mais de 120 mil pessoas no Discord.
Acesso ilimitado ao catálogo de Imersões da Alura para praticar conhecimentos em diferentes áreas.
Explore um universo de possibilidades na palma da sua mão. Baixe as aulas para assistir offline, onde e quando quiser.
Acelere o seu aprendizado com a IA da Alura e prepare-se para o mercado internacional.
1 ano de Alura
Todos os benefícios do PLUS e mais vantagens exclusivas:
Luri é nossa inteligência artificial que tira dúvidas, dá exemplos práticos, corrige exercícios e ajuda a mergulhar ainda mais durante as aulas. Você pode conversar com a Luri até 100 mensagens por semana.
Aprenda um novo idioma e expanda seus horizontes profissionais. Cursos de Inglês, Espanhol e Inglês para Devs, 100% focado em tecnologia.
Para estudantes ultra comprometidos atingirem seu objetivo mais rápido.
1 ano de Alura
Todos os benefícios do PRO e mais vantagens exclusivas:
Mensagens ilimitadas para estudar com a Luri, a IA da Alura, disponível 24hs para tirar suas dúvidas, dar exemplos práticos, corrigir exercícios e impulsionar seus estudos.
Envie imagens para a Luri e ela te ajuda a solucionar problemas, identificar erros, esclarecer gráficos, analisar design e muito mais.
Escolha os ebooks da Casa do Código, a editora da Alura, que apoiarão a sua jornada de aprendizado para sempre.
Conecte-se ao mercado com mentoria personalizada, vagas exclusivas e networking estratégico que impulsionam sua carreira tech para o próximo nível.