Animating Apps With Flutter
About The Author
Uma pilha completa de desenvolvimento de software durante o dia e de aplicações móveis durante a noite. Embora não esteja trabalhando, eu adoro cozinhar e jogar jogos para PC.Mais aboutShubham↬
- 14 min read
- Apps,Animação
- Salvado para leitura offline
- Partilhar no Twitter, LinkedIn
Aplicações para qualquer plataforma são elogiadas quando são intuitivas, de boa aparência e fornecem um feedback agradável para as interações do usuário. Animação é uma das formas de fazer exatamente isso.
Flutter, uma estrutura multiplataforma, amadureceu nos últimos dois anos para incluir suporte web e desktop. Ganhou uma reputação de que os aplicativos desenvolvidos com ele são suaves e bonitos. Com seu rico suporte a animação, forma declarativa de escrever UI, “Hot Reload,” e outros recursos, é agora um framework completo para várias plataformas.
Se você está começando com Flutter e quer aprender uma forma não convencional de adicionar animação, então você está no lugar certo: nós vamos explorar o reino da animação e widgets de movimento, uma forma implícita de adicionar animações.
Flutter é baseado no conceito de widgets. Cada componente visual de um aplicativo é um widget – pense neles como vistas no Android. Flutter fornece suporte a animação usando uma classe de Animação, um objeto “AnimationController” para gerenciamento, e “Tween” para interpolar a gama de dados. Estes três componentes trabalham em conjunto para fornecer uma animação suave. Uma vez que isto requer a criação e gestão manual de animação, é conhecida como uma forma explícita de animação.
Agora deixe-me apresentar-lhe os widgets de animação e movimento. Flutter fornece inúmeros widgets que suportam inerentemente animação. Não há necessidade de criar um objecto de animação ou qualquer controlador, pois toda a animação é tratada por esta categoria de widgets. Basta escolher o widget apropriado para a animação desejada e passar nos valores das propriedades do widget para animar. Esta técnica é uma forma implícita de animar.
O gráfico acima apresenta de forma aproximada a hierarquia da animação em Flutter, como ambas as animações explícitas e implícitas são suportadas.
Alguns dos widgets animados abordados neste artigo são:
-
AnimatedOpacity
-
AnimatedCrossFade
AnimatedAlign
AnimatedPadding
-
AnimatedSize
-
AnimatedPositioned
.
Flutter não só fornece widgets animados predefinidos, mas também um widget genérico chamado AnimatedWidget
, que pode ser usado para criar widgets animados personalizados implicitamente. Como o nome indica, estes widgets pertencem à categoria de widgets animados e de movimento, e por isso têm algumas propriedades comuns que nos permitem tornar as animações muito mais suaves e com melhor aspecto.
Deixe-me explicar estas propriedades comuns agora, pois serão usadas mais tarde em todos os exemplos.
-
duration
A duração sobre a qual animar os parâmetros. -
reverseDuration
A duração da animação inversa. -
curve
A curva a aplicar ao animar os parâmetros. Os valores interpolados podem ser tomados de uma distribuição linear ou, se e quando especificados, podem ser tomados de uma curva.
Vamos começar a jornada criando um aplicativo simples que chamaremos de “Citado”. Ele exibirá uma citação aleatória toda vez que a aplicação for iniciada. Duas coisas a notar: primeiro, todas essas citações serão codificadas no aplicativo; e segundo, nenhum dado do usuário será salvo.
Note: Todos os arquivos para esses exemplos podem ser encontrados no GitHub.
Get Started
Flutter deve ser instalado e você precisará de alguma familiaridade com o fluxo básico antes de seguir em frente. Um bom lugar para começar é, “Using Google’s Flutter For Truly Cross-Platform Mobile Development”.
Criar um novo projeto Flutter no Android Studio.
Agenda um novo assistente de projeto, onde você pode configurar o básico do projeto.
Na tela de seleção do tipo de projeto, existem vários tipos de projetos Flutter, cada um atendendo a um cenário específico… Para este tutorial, escolha Flutter Application e pressione Next.
Precisa agora de introduzir alguma informação específica do projecto: o nome do projecto e o caminho, o domínio da empresa, etc. Dê uma olhada na imagem abaixo.
Adicionar o nome do projeto, o caminho do Flutter SDK, a localização do projeto e uma descrição opcional do projeto. Pressione Next.
Cada aplicação (seja Android ou iOS) requer um nome de pacote único. Normalmente, você usa o reverso do domínio do seu site; por exemplo, com.google ou com.yahoo. Pressione Finish para gerar um aplicativo Flutter funcional.
Após o projeto ser gerado, você deve ver a tela mostrada acima. Abra o arquivo main.dart (destacado na captura de tela). Este é o arquivo principal da aplicação. O projeto de exemplo é completo em si mesmo, e pode ser executado diretamente em um emulador ou dispositivo físico sem qualquer modificação.
Substitua o conteúdo do arquivo main.dart pelo seguinte código snippet:
import 'package:animated_widgets/FirstPage.dart';import 'package:flutter/material.dart';void main() => runApp(MyApp());class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Animated Widgets', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, accentColor: Colors.redAccent, ), home: FirstPage(), ); }}
Este código limpa o arquivo main.dart simplesmente adicionando informações simples relevantes para a criação de um novo aplicativo. A classe MyApp retorna um objeto: um widget MaterialApp
, que fornece a estrutura básica para a criação de aplicativos em conformidade com o Material Design. Para tornar o código mais estruturado, crie dois novos arquivos de dardos dentro da pasta lib: FirstPage.dart e Quotes.dart.
FirstPage.dart conterá todo o código responsável por todos os elementos visuais (widgets) necessários para o nosso aplicativo Quoted. Toda a animação é tratada neste arquivo.
Note: Mais tarde no artigo, todos os trechos de código para cada widget animado são adicionados a este arquivo como filhos do widget Scaffold. Para mais informações, este exemplo no GitHub pode ser útil.
Inicie adicionando o seguinte código ao FirstPage.dart. Este é o código parcial onde outras coisas serão adicionadas mais tarde.
import 'dart:math';import 'package:animated_widgets/Quotes.dart';import 'package:flutter/material.dart';class FirstPage extends StatefulWidget { @override State createState() { return FirstPageState(); }}class FirstPageState extends State with TickerProviderStateMixin { bool showNextButton = false; bool showNameLabel = false; bool alignTop = false; bool increaseLeftPadding = false; bool showGreetings = false; bool showQuoteCard = false; String name = ''; double screenWidth; double screenHeight; String quote; @override void initState() { super.initState(); Random random = new Random(); int quoteIndex = random.nextInt(Quotes.quotesArray.length); quote = Quotes.quotesArray; } @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; screenHeight = MediaQuery.of(context).size.height; return Scaffold( appBar: _getAppBar(), body: Stack( children: , ), ); }}
O arquivo Quotes.dart contém uma lista de todas as citações hardcoded. Um ponto a notar aqui é que a lista é um objecto estático. Isto significa que ela pode ser usada em outros lugares sem criar um novo objeto da classe Quotes. Isto é escolhido por design, pois a lista acima age simplesmente como um utilitário.
Adicionar o seguinte código a este ficheiro:
class Quotes { static const quotesArray = ;}
O esqueleto do projecto está agora pronto, por isso vamos dar um pouco mais de profundidade Citações.
AnimatedOpacity
Para dar um toque pessoal à aplicação, seria bom saber o nome do utilizador, por isso vamos pedi-lo e mostrar um próximo botão. Até o usuário digitar seu nome, este botão fica oculto, e aparecerá graciosamente quando um nome for dado. Precisamos de algum tipo de animação de visibilidade para o botão, mas existe algum widget para isso? Sim, existe.
Enter AnimatedOpacity
. Este widget é construído sobre o widget Opacity adicionando suporte implícito à animação. Como é que o usamos? Lembre-se do nosso cenário: precisamos de mostrar um próximo botão com visibilidade animada. Embrulhamos o botão widget dentro do widget AnimatedOpacity
, alimentamos em alguns valores apropriados e adicionamos uma condição para acionar a animação – e Flutter pode lidar com o resto.
_getAnimatedOpacityButton() { return AnimatedOpacity( duration: Duration(seconds: 1), reverseDuration: Duration(seconds: 1), curve: Curves.easeInOut, opacity: showNextButton ? 1 : 0, child: _getButton(), );}
O AnimatedOpacity
widget tem duas propriedades obrigatórias:
-
opacity
Um valor de 1 significa completamente visível; 0 (zero) significa oculto. Enquanto anima, Flutter interpola valores entre estes dois extremos. Você pode ver como uma condição é colocada para alterar a visibilidade, desencadeando assim a animação. -
child
O widget criança que terá a sua visibilidade animada.
Você deve agora entender como é realmente simples adicionar animação de visibilidade com o widget implícito. E todos esses widgets seguem as mesmas diretrizes e são fáceis de usar. Vamos passar para o próximo.
AnimatedCrossFade
Temos o nome do usuário, mas o widget ainda está esperando por entrada. No passo anterior, quando o usuário digita seu nome, nós mostramos o próximo botão. Agora, quando o usuário apertar o botão, quero parar de aceitar a entrada e mostrar o nome inserido. Há muitas maneiras de fazê-lo, é claro, mas talvez possamos esconder o widget de entrada e mostrar um widget de texto não editável. Vamos experimentar usando o widget AnimatedCrossFade
widget.
Este widget requer dois filhos, já que o widget se cruza entre eles com base em alguma condição. Uma coisa importante a ter em mente ao usar este widget é que ambas as crianças devem ter a mesma largura. Se a altura é diferente, então o widget mais alto é cortado de baixo. Neste cenário, dois widgets serão usados como crianças: input e label.
_getAnimatedCrossfade() { return AnimatedCrossFade( duration: Duration(seconds: 1), alignment: Alignment.center, reverseDuration: Duration(seconds: 1), firstChild: _getNameInputWidget(), firstCurve: Curves.easeInOut, secondChild: _getNameLabelWidget(), secondCurve: Curves.easeInOut, crossFadeState: showNameLabel ? CrossFadeState.showSecond : CrossFadeState.showFirst, );}
Este widget requer um conjunto diferente de parâmetros obrigatórios:
-
crossFadeState
Este estado determina qual criança mostrar. -
firstChild
Especifica a primeira criança para este widget. -
secondChild
Especifica a segunda criança.
Alinhamento Animizado
Neste ponto, a etiqueta do nome é posicionada no centro da tela. Ela ficará muito melhor no topo, pois precisamos do centro da tela para mostrar as citações. Simplificando, o alinhamento do widget da etiqueta do nome deve ser mudado do centro para o topo. E não seria bom animar esta mudança de alinhamento juntamente com a animação anterior de cross-fade? Vamos fazer isso.
Como sempre, várias técnicas podem ser usadas para conseguir isso. Como o nome widget de etiqueta já está alinhado ao centro, animar o seu alinhamento seria muito mais simples do que manipular os valores superior e esquerdo do widget. O widget AnimatedAlign
é perfeito para este trabalho.
Para iniciar esta animação, um gatilho é necessário. O único propósito deste widget é animar a mudança de alinhamento, então ele tem apenas algumas propriedades: adicionar uma criança, definir seu alinhamento, acionar a mudança de alinhamento, e pronto.
_getAnimatedAlignWidget() { return AnimatedAlign(duration: Duration(seconds: 1),curve: Curves.easeInOut,alignment: alignTop ? Alignment.topLeft : Alignment.center,child: _getAnimatedCrossfade(), );}
Tem apenas duas propriedades obrigatórias:
- criança:
A criança cujo alinhamento será modificado. - alinhamento:
Alinhamento requerido.
Este widget é realmente simples mas os resultados são elegantes. Além disso, vimos como podemos facilmente usar dois widgets animados diferentes para criar uma animação mais complexa. Esta é a beleza dos widgets animados.
AnimatedPadding
Agora temos o nome do usuário no topo, suavemente animado sem muito esforço, usando diferentes tipos de widgets animados. Vamos adicionar uma saudação, “Olá”, antes do nome. Adicionando um widget de texto com o valor “Olá”, no topo irá sobrepor o widget de texto de saudação, parecido com a imagem abaixo.
E se o widget de texto de saudação tivesse algum acolchoamento à esquerda? Aumentar o acolchoamento à esquerda vai definitivamente funcionar, mas espere: podemos aumentar o acolchoamento com alguma animação? Sim, e isso é o que AnimatedPadding
faz. Para tornar tudo isso muito mais bonito, vamos fazer com que o widget de texto de saudação desapareça e o padding do nome widget de texto aumente ao mesmo tempo.
_getAnimatedPaddingWidget() { return AnimatedPadding( duration: Duration(seconds: 1), curve: Curves.fastOutSlowIn, padding: increaseLeftPadding ? EdgeInsets.only(left: 28.0) : EdgeInsets.only(left: 0), child: _getAnimatedCrossfade(), );}
Desde que a animação acima só deve ocorrer após o alinhamento animado anterior estar completo, precisamos atrasar o acionamento dessa animação. Digerindo do tópico brevemente, este é um bom momento para falar sobre um mecanismo popular para adicionar atraso. Flutter fornece várias dessas técnicas, mas o construtor Future.delayed é uma das abordagens mais simples, mais limpa e mais legível. Por exemplo, para executar uma peça de código após 1 segundo:
Future.delayed(Duration(seconds: 1), (){ sum = a + b; // This sum will be calculated after 1 second. print(sum);});
Desde que a duração do atraso já seja conhecida (calculada a partir de durações de animação anteriores), a animação pode ser acionada após esse intervalo.
// Showing "Hi" after 1 second - greetings visibility trigger._showGreetings() { Future.delayed(Duration(seconds: 1), () { setState(() { showGreetings = true; }); });}// Increasing the padding for name label widget after 1 second - increase padding trigger._increaseLeftPadding() { Future.delayed(Duration(seconds: 1), () { setState(() { increaseLeftPadding = true; }); });}
Este widget tem apenas duas propriedades obrigatórias:
-
child
A criança dentro deste widget, ao qual o acolchoamento será aplicado. -
padding
A quantidade de espaço a adicionar.
AnimatedSize
Hoje em dia, qualquer aplicativo que tenha algum tipo de animação incluirá o zoom para dentro ou para fora dos componentes visuais para captar a atenção do usuário (comumente chamado de animação em escala). Por que não usar a mesma técnica aqui? Podemos mostrar ao usuário uma citação motivacional que faz zoom a partir do centro da tela. Deixe-me apresentar-lhe o widget AnimatedSize
, que permite os efeitos de zoom-in e zoom-out, controlados alterando o tamanho do seu filho.
Este widget é um pouco diferente dos outros quando se trata dos parâmetros necessários. Precisamos do que o Flutter chama de “Ticker”. O Flutter tem um método para que os objetos saibam sempre que um novo evento de frame é acionado. Pode ser pensado como algo que envia um sinal dizendo: “Faça-o agora! … Faça-o agora! … Faça-o agora! …”
O widget AnimatedSize
requer uma propriedade – vsync – que aceita um provedor de ticker. A maneira mais fácil de obter um provedor de ticker é adicionar um Mixin à classe. Existem duas implementações básicas de provedor de ticker: SingleTickerProviderStateMixin
, que fornece um único ticker; e TickerProviderStateMixin
, que fornece vários.
A implementação padrão de um ticker é usada para marcar os frames de uma animação. Neste caso, este último é utilizado. Mais sobre mixins.
// Helper method to create quotes card widget._getQuoteCardWidget() { return Card( color: Colors.green, elevation: 8.0, child: _getAnimatedSizeWidget(), );}// Helper method to create animated size widget and set its properties._getAnimatedSizeWidget() { return AnimatedSize( duration: Duration(seconds: 1), curve: Curves.easeInOut, vsync: this, child: _getQuoteContainer(), );}// Helper method to create the quotes container widget with different sizes._getQuoteContainer() { return Container( height: showQuoteCard ? 100 : 0, width: showQuoteCard ? screenWidth - 32 : 0, child: Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text(quote, style: TextStyle(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 14),), ), ), );}// Trigger used to show the quote card widget._showQuote() { Future.delayed(Duration(seconds: 2), () { setState(() { showQuoteCard = true; }); });}
Propriedades obrigatórias para este widget:
-
vsync
O fornecedor do ticker necessário para coordenar animação e mudanças de quadros.< -
child
A criança cujo tamanho muda será animada.
A animação de aumentar e diminuir é agora facilmente domada.
AnimadaPosicionada
Grande! As aspas aumentam a partir do centro para chamar a atenção do usuário. E se deslizasse para cima a partir de baixo enquanto faz zoom in? Vamos tentar. Este movimento envolve brincar com a posição do widget de citações e animar as mudanças nas propriedades de posição. AnimatedPositioned
é o candidato perfeito.
Este widget transita automaticamente a posição da criança ao longo de uma determinada duração sempre que a posição especificada muda. Um ponto a notar: ele só funciona se o widget pai for um “Stack”. Este widget é bastante simples e direto de usar. Vejamos.
// Helper method to create the animated positioned widget.// With position changes based on "showQuoteCard" flag._getAnimatedPositionWidget() { return AnimatedPositioned( duration: Duration(seconds: 1), curve: Curves.easeInOut, child: _getQuoteCardWidget(), top: showQuoteCard ? screenHeight/2 - 100 : screenHeight, left: !showQuoteCard ? screenWidth/2 : 12, );}
Este widget tem apenas uma propriedade obrigatória:
-
child
O widget cuja posição será alterada.
Se não se espera que o tamanho da criança mude juntamente com a sua posição, uma alternativa mais performativa a este widget seria SlideTransition
.
Aqui está a nossa animação completa:
Conclusão
Animações são parte integrante da experiência do usuário. Aplicações estáticas ou aplicações com animação janky não só menor retenção de usuários, mas também a reputação de um desenvolvedor para entregar resultados.
Hoje, a maioria das aplicações populares têm algum tipo de animação sutil para encantar os usuários. O feedback animado aos pedidos dos usuários também pode envolvê-los para explorar mais. Flutter oferece um monte de recursos para desenvolvimento multiplataforma, incluindo suporte rico para animações suaves e responsivas.
Flutter tem ótimo suporte a plug-in que nos permite usar animações de outros desenvolvedores. Agora que ele amadureceu para a versão 1.9, com tanto amor da comunidade, Flutter está destinado a melhorar no futuro. Eu diria que agora é um ótimo momento para aprender Flutter!
Leave a Reply