Alura > Cursos de Mobile > Cursos de Flutter > Conteúdos de Flutter > Primeiras aulas do curso Flutter: crie animações implícitas avançadas e microinterações

Flutter: crie animações implícitas avançadas e microinterações

Animações implícitas avançadas - Apresentação

Olá! Meu nome é Ricarth Lima e serei seu instrutor em mais um curso de Flutter!

Audiodescrição: Ricarth se autodescreve como um homem de cabelo crespo e volumoso. Usa óculos de armação escura, tem um cavanhaque com barba por fazer, veste uma camiseta preta e está em um cenário com iluminação entre o rosa e o roxo.

Agora que já nos conhecemos, boas-vindas ao curso de Flutter com animações implícitas avançadas.

Projeto do curso

O projeto do curso é o "Meu pequeno Grimório". Este curso será uma continuação direta do primeiro curso da formação. Portanto, continuaremos com esse projeto de registro de livros com um toque lúdico, de magia.

Nossos objetivos serão, primeiro, abrir um dialog de forma animada. Para isso, vamos aprender a usar alguns widgets de animação implícita, entenderemos o que é o TweenAnimationBuilder e como podemos usá-lo para simplificar algumas animações que podem se tornar mais complexas se usarmos os widgets específicos, os quais estamos acostumados.

Além disso, quando o dialog estiver implementado, perceberemos que animá-lo não é tão trivial quanto parece. Portanto, este conhecimento será muito útil, já que dialog é algo que usamos muito no Flutter.

Em seguida, vamos criar uma microinteração que é um tremor. Ele serve para que a pessoa usuária saiba que algo vai acontecer quando ela clicar e segurar na capa do livro.

O interessante é que, com essa microinteração, vamos poder aprofundar os conhecimentos de animações implícitas, de TweenAnimationBuilder, além de criarmos nossa curva personalizada. Já imaginou que podemos personalizar nossas curvas?

Conhecer todas essas ferramentas será bastante útil para que, quando um problema surgir, saibamos resolver com as ferramentas que temos. Incrível, não é?!

Pré-requisitos

Os pré-requisitos são as formações Dart e Flutter. Com elas, já teremos uma base sólida para continuar. É claro, o primeiro curso da formação de Flutter com animações, onde começamos este projeto. É muito importante que já tenha passado por ele, porque vários conceitos que vamos usar aqui já foram apresentados lá.

Agora estamos prontas e prontos! Se gostar deste curso e se animar com o projeto, não se esqueça de participar das nossas comunidades no Fórum e no Discord, e usar a hashtag #AprendiNaAlura. Acompanhar o seu progresso é muito satisfatório para nós.

Este curso será incrível. Até lá!

Animações implícitas avançadas - Preparando o aplicativo para as novas implementações

Ótimo! Temos um Grimório, mas ele está vazio. Para implementar as funcionalidades desejadas, precisamos preenchê-lo com alguns livros. Vamos fazer isso?

Com o emulador aberto, vamos clicar em "Entrar" na nossa tela de onboarding. Como ainda não implementamos o login, essa tela serve mais como exemplo, então, apertaremos "Entrar" outra vez.

Dois livros já foram adicionados. Para adicionar um livro, basta clicar no símbolo de "mais (+)". Na busca, procuramos pelo livro que desejamos adicionar.

Vou adicionar um interessante de RPG, que é "Os monstros sabem o que estão fazendo". Basicamente, se trata de um livro para pessoas mestras de RPG, para criar melhores combates com os monstros. Vamos clicar nele. Ao clicar, aparecem a descrição, a capa, o título, a autoria e o resumo. Clicaremos em adicionar livro.

Após clicar em adicionar livro, rolando a tela para baixo, visualizaremos a descrição, depois o início o final da leitura e os comentários. Vamos clicar em início da leitura e selecionar uma data clicando no calendário que apareceu à direita. Suponhamos que começamos a ler no início do mês. Vamos clicar no dia 1 e em "OK".

Para o final da leitura, vamos clicar no calendário, selecionar a data de hoje e apertar "OK". Em "Comentários", logo abaixo, podemos escrever, por exemplo: "Muito bom para desafiar meus jogadores". Depois disso, é só clicar em "Adicionar".

Pronto. Agora temos três livros. Recomendamos que você repita esses passos uma ou duas vezes para ter pelo menos dois ou três livros, assim conseguiremos trabalhar adequadamente.

Resumindo, adicionamos livros e agora podemos trabalhar na funcionalidade de mostrar a capa com destaque. É exatamente isso que começaremos a fazer em seguida. Te vejo lá.

Animações implícitas avançadas - Criando o dialog de capa de livro

Ótimo! Agora nós preenchemos nosso Grimório com alguns livros e queremos implementar a funcionalidade de expandir a capa para visualizarmos melhor os detalhes.

Ainda não temos isso implementado. Se clicamos e seguramos na capa, nada acontece. Então, qual é o primeiro passo? Lembrando que esse projeto veio semi-pronto. Nossa missão é animá-lo, é criar as animações e as microinterações. Precisamos descobrir onde estão esses itens. Qual é a tela? O que esse widget representa? Como ele está funcionando?

Para fazer isso, vamos no nosso VSCode. No canto superior esquerdo, abriremos o "Explorer". Temos uma boa organização, com controller, dao, models e screens. O Screens (Telas) é uma boa dica, já que estamos procurando a tela. Então, clicamos na pasta Screens. Podemos arrastar um pouco para o lado a barra do Explorer apenas para melhorar a visualização.

Procurando melhor entre as pastas, encontraremos um chamado Home. Uma das pastas se chama home.dart, é uma boa pista. Abrimos o arquivo Home e podemos fechar o explorador para analisá-lo melhor.

Rolando o código para baixo, vamos notar que existe um widget chamado Filled Home widget. Basicamente, é a tela quando a Home tem livros para mostrar, quando ela está preenchida. O que é diferente daquele status que estava antes, quando ela estava vazia.

// Código omitido. 

// Filled Home widget
class_FilledHome extends StatefulWidget {
  _FilledHome((required this.listPersonalBook));
    
List<PersonalBook> listPersonalBook;

@override
State<_FilledHome> createState( => _FilledHomeState();
}

// Código omitido. 

Para consultar o arquivo completo, basta acessar o GitHub do curso.

Então, analisando o código, notamos que a tela uma lista de PersonalBook que representam justamente aqueles livros que adicionamos. Onde estão esses livros? Quais são esses widgets? Vamos rolar mais para baixo.

Se formos até a linha 92, encontraremos um builder de Grid.

// Código omitido. 

SliverGrid.builder(
                itemCount: widget.listPersonalBook.length,
                gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 3,
                  mainAxisExtent: 167,
                  mainAxisSpacing: 16,
                  crossAxisSpacing: 16,
                ),
                itemBuilder: (context, index) => InkWell(
                  onLongPress: () {
                    showCoverDialog(
                      context: context,
                      urlImage: widget
                          .listPersonalBook[index].googleBook.thumbnailLink,
                    );

// Código omitido. 

É uma boa pista, porque o que está sendo criado é justamente um Grid. E, se chegarmos no itemBuilder desse Grid, vamos perceber que ele está criando um InkWell com uma imagem como fillho ou child.

// Código omitido. 

  itemBuilder: (context, index) => InkWell(
                  onLongPress: () {
                    showCoverDialog(
                      context: context,
                      urlImage: widget
                          .listPersonalBook[index].googleBook.thumbnailLink,
                    );
                  },
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => BookDetails(
                          personalBook: widget.listPersonalBook[index],
                        ),
                      ),
                    ).then((value) async {
                      widget.listPersonalBook = await bookController.getBooks();
                      setState(() {});
                    });
                  },
                  child: Image.network(
                    widget.listPersonalBook[index].googleBook.thumbnailLink,
                    height: 220,
                    width: 144,
                    fit: BoxFit.cover,
                  ),
                ),
              ),
            ],
          ),
        ),
        Positioned(
          bottom: 0,
          child: Container(
            height: 72,
            width: MediaQuery.of(context).size.width,
            decoration: HomeShadowProperties.boxDecoration,
          ),
        ),
        Positioned(
          top: MediaQuery.of(context).size.height - 125,
          left: MediaQuery.of(context).size.width / 2 - 28,
          child: FloatingButton(
            onTap: () {
              Navigator.push(context,
                  MaterialPageRoute(builder: (context) => const SearchBooks()));
            },
          ),
        ),
      ],
    );
  }
}

// Código omitido. 

Então, há um InkWell na linha 100 e uma imagem como "filho" na linha 114. É aqui mesmo que está nosso widget! Inclusive, o clique no onTap na linha 101, leva para a outra página na linha 102. Então, com certeza é aqui mesmo.

Se queremos dar um comportamento de clicar e pressionar, sabemos que precisamos, no nosso InkWell, adicionar outro callback para justamente o que vai acontecer quando clicarmos e pressionarmos. Na linha 100, vamos dar "enter" e escrever OnLongPress, por enquanto, como uma função vazia. Mas essa função vai ser executada quando clicarmos e pressionarmos.

// Código omitido. 

itemBuilder: (context, index) => InkWell(
  onLongPress: () {},
  onTap: () {

// Código omitido. 

Só que precisamos criar, de fato, esse comportamento de mostrar o dialog com uma imagem. Para isso, vamos abrir mais uma vez o nosso Explorer. Acessaremos "components", já que isso é um componente, não é uma tela inteira e quem fez o projeto organizou assim. Vale seguir a organização.

Vamos clicar com o botão esquerdo na pasta "components", selecionar "New File" e escrever "cover_dialog", pois se trata de um dialog que vai abrir com a capa em inglês.

Podemos fechar o nosso Explorer no canto superior esquerdo mais uma vez. E agora vamos criar, de fato, uma função: showCoverDialog(), que vai chamar um showDialog que nós já conhecemos bem.

import package:flutter/material.dart';

showCoverDialog(){
  showDialog(context: context, builder: builder)
}

Ele precisa de um contexto construtor, então, vamos pedir um required BuildContext context por parâmetro.

import package:flutter/material.dart';

showCoverDialog({required BuildContext context){
  showDialog(context: context, builder: builder)
}

Podemos apagar o builder que está pedindo um construtor na linha 4, dar um "contra-espaço" e pegar um dos padrões que ele nos sugere, por exemplo, a função completa, sem error.

import package:flutter/material.dart';

showCoverDialog({required BuildContext context){
  showDialog(context: context, builder: (context) {
    
  },
 );
}

Temos também que fazer o retorno. Então, na linha 7, vamos dar um return Dialog().

import package:flutter/material.dart';

showCoverDialog({required BuildContext context){
  showDialog(context: context, builder: (context) {
     context: context,
     builder: (context) {
       return Dialog()
    
  },
 );
}

Não vamos usar nem a OtherDialog(), nem a AboutDialog(), porque queremos criar esse dialog do zero mesmo.

O que esperamos ter como filho desse dialog? Uma imagem. Queremos uma imagem. Então, vamos colocar um Child: Image.network(src).

import package:flutter/material.dart';

showCoverDialog({required BuildContext context){
  showDialog(context: context, builder: (context) {
     context: context,
     builder: (context) {
       return Dialog()
           child: Image.network(src)
              // Dialog
    
  },
 );
}

Só que ainda não temos a fonte dessa imagem. Ela está na outra tela. Vamos pedir por parâmetro. Então, na linha 3, vamos colocar uma vírgula seguida de required String urlImage. Também passaremos urlImage como parâmetro em Image.network().

import package:flutter/material.dart';

showCoverDialog({required BuildContext context, required String urlImage){
  showDialog(
     context: context,
     builder: (context) {
       return Dialog()
           child: Image.network(urlImage)
              // Dialog
    
  },
 );
}

Com o arquivo salvo, voltaremos para a Home. Dentro do nosso onLongPress, vamos dar um "Enter" e chamar ShowCoverDialog(). E já estamos passando o contexto. A urlImage, vamos ter que descobrir como conseguimos.

No itemCount há um widget que pega do nosso ListPersonalBook. Supomos que essa lista vai ter os objetos que contêm todas essas informações, inclusive a imagem. Mas, se rolássemos o código um pouco para baixo, na linha 119, dentro da imagem que já é mostrada, encontraríamos o link da imagem.

Então, é o widget.listPersonalBook na posição index, já que isso é um grid, .googlebook.thumbnail link. Então, vamos copiar toda a linha 119 para ganhar tempo.

Subimos aqui na linha 103 e, na urlImage, colamos. Podemos adicionar vírgula para quebrar e colocar um ponto e vírgula para ele parar de dar erro.

import package:flutter/material.dart';

showCoverDialog({required BuildContext context, required String urlImage: widget.listPersonalBook[index].googleBook.thumbnailLink,
 );
 },
  showDialog(
     context: context,
     builder: (context) {
       return Dialog()
           child: Image.network(urlImage)
              // Dialog
    
  },
 );
}

Vamos salvar e conferir se funcionou. Vamos abrir o nosso emulador, clicar e segurar em qualquer um dos livros. Estamos chegando em algum lugar: já conseguimos clicar, pressionar e fazer aparecer uma imagem.

Não está 100% do jeito que queremos, mas vamos ter que editar esse dialog para que ele apareça exatamente do jeito que queremos. É justamente isso que vamos fazer logo na sequência. Até lá!

Sobre o curso Flutter: crie animações implícitas avançadas e microinterações

O curso Flutter: crie animações implícitas avançadas e microinterações possui 115 minutos de vídeos, em um total de 48 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:

Aprenda Flutter acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas