Fique à vontade para começar a leitura de onde tiver mais interesse. Este artigo é extenso cobre diversos assuntos!
O que você vai encontrar neste artigo?
- Por que e como devemos utilizar motion na interface do nosso app;
- O que é uma animação;
- Diferença entre a animação tradicional e UI Motion;
- UIView.animate e UIViewPropertyAnimator;
- As bibliotecas mais utilizadas para animação;
- Download do projeto.
Este artigo foi feito com foco em iOS mas pode ser aplicado a outras plataformas bem como pode ser lido tanto por Desenvolvedores quanto Designers.
Aos designers: veja como fazemos implementações mesmo sem entender programação e saiba quais são as possibilidades.
Aos devs: é um bom diferencial no seu projeto a utilização de bons componentes de interface e a criação de uma boa experiência. Que tal começar por animações?
Por que devemos utilizar motion?
- Melhora a experiência e destaca nosso app dos outros;
- Chama a atenção dos usuários para um ponto específico. Por exemplo: um alerta demonstrando que o usuário pode interagir com algo;
- Dá vida à interface do seu app.
Esta frase nunca fez tanto sentido. Quando utilizamos corretamente as animações no nosso aplicativo, conseguimos nos aproximar das pessoas simplesmente por ser algo natural. As pessoas param de ver a tecnologia como algo frio e passam a ver como algo tátil e mais próximos dela.
Agora sabemos o porquê, mas onde deveríamos aplicar o motion?
Como devemos utilizar motion?
- Para criação de onboardings ou coachmarks, ou seja, podemos guiar e ensinar o usuário a como navegar e utilizar as features do nosso app;
- Fornecer status de sistema. Ao fazer upload de uma imagem ou o download de um arquivo o usuário quer saber o status desta ação;
- Dar feedback visual às interações. Quando clicamos em um botão na vida real gostaríamos de ter uma resposta. Não é diferente no aplicativo;
- Melhorar a navegação. Ao clicar em um botão, por exemplo, por que não fazer uma transição até a outra tela?;
- Atente-se, as animações devem fazer sentido e devem ter um propósito;
- Não devemos abusar do motion. Motion é legal mas isso não quer dizer que devemos transformar nosso app num carnaval.
Agora que sabemos os motivos e as aplicações, vamos para o básico:
O que é uma animação?
Uma animação é uma sequência de imagens em posições diferentes que dá a sensação de movimento. Cada imagem seria um frame da nossa animação. Quanto menos diferença entre os frames mais suave será a nossa animação. Lembra daqueles flipbooks em que cada página é um desenho em posições diferentes? É assim que funciona.
Cenário real
Imagine que você está navegando pela sua rede social favorita e se depara com o botão de “like” em formato de coração. Ao clicar, o botão fica vermelho e mostra que a ação foi bem sucedida. A animação? Foi simples. O ícone simplesmente ficou vermelho com uma transição suave, um fade in.
Acredita que se fizermos pequenas mudanças nessa animação a experiência consegue se tornar única? Foi o que Twitter e Google (Material Design) fizeram.
Motion não é só fazer as animações. É brincar com as formas e fazer com que seja algo divertido.
Falamos de animações e motion por aqui, percebeu? Mas, afinal, possui alguma diferença?
Diferença entre animação tradicional e UI Motion
Apesar de chamarmos tudo de animação, possui algumas pequenas diferenças sim. O UI Motion é um tipo de animação, porém, não conta histórias e muito menos tem um começo, meio e fim. O UI Motion tem como objetivo animar formas abstratas.
Animação tradicional
A animação tradicional segue os princípios da animação tradicional. Puxar, esticar, exagerar, entre outros… Você pode conferir mais neste artigo incrível.
Quando falamos em animação tradicional lembramos logo do Mickey, da Disney. O objetivo nesses desenhos era dar vida aos personagens inanimados, então esse estilo “cartoonesco” não é atoa.
UI Motion
Por outro lado, o UI Motion tem como foco o usuário. Também existem princípios para Motion, podem ser lidos aqui.
Garanto que ao fazer animações em algum projeto você já se deparou com alguns dos princípios acima. Mas por ora vamos focar no primeiro: Easing.
Easing
Na vida real, nada começa e para do nada. Todos objetos tem uma aceleração e uma desaceleração. Nós somos atraídos por movimento de forma natural e essa naturalidade deveria ser levada por nós para o código ao fazer nossas animações. Mas como fazer isso?
Bézier Curves
Felizmente conseguimos reproduzir aceleração/desaceleração na programação. A curva cúbica de bézier é, de forma simples, uma reta que vai do ponto mais baixo (x: 0, y: 0) até o ponto mais alto (x: 1, y: 1) de uma matriz progresso x tempo. Esses pontos são chamados pontos de controle. Os pontos de controle possuem as posições (x,y) como mostrados acima. Ao mexer neles e mudar essa posição, é realizada uma equação que resulta numa curva. Abaixo, podemos ver uma curva bézier EASE IN, modelo de curva muito utilizado. Repare as posições (x,y) dos pontos de controle:
Bézier curves utilizando Core Animation Transaction
De forma nativa conseguimos reproduzir as curvas acima e para isso que vamos utilizar o CA Transaction.
Acesse o site https://cubic-bezier.com/ para criar curvas personalizadas e conseguir os números escolhidos. Agora, escreva o código abaixo:
let timeFunc = CAMediaTimingFunction(controlPoints: 0.42, 0, 1, 1)
CATransaction.setAnimationTimingFunction(timeFunc)
Criamos um objeto de CAMediaTimingFunction(controlPoints:) passando como parâmetro as posições (c1: x, y, c2: x, y), ou seja, passamos os eixos de cada ponto de controle da nossa matriz acima. Já está funcionando!
Todas as animações que você colocar abaixo receberão esta curva customizada. Quando a ultima animação for executada, o método removerá essa curva e voltará para a padrão (linear). Caso você queira remover a animação explicitamente, utilize o método abaixo:
CATransaction.flush()
Exemplo real utilizando Bézier Curves
Abaixo temos um exemplo real de como utilizar o código acima com diferentes curvas bézier. Fizemos uma barra de carregamento com curva linear e uma barra utilizando uma curva customizada. Repare a diferença.
Começando com UIView.animate
Implementação básica
Você, dev, já deve ter se deparado com esse código:
UIView.animate(withDuration: 1) {
// Sua animação aqui
}
É a forma mais alto nível de fazer uma animação em iOS. Apenas passando a duração como parâmetro conseguimos, por exemplo, mexer no frame.y de uma view.
Implementação com mais argumentos
Para implementarmos curvas, delay e outras opções, poderemos passar mais argumentos como parâmetro:
UIView.animate(withDuration: 1,
delay: 0,
options: [.curveEaseIn, .repeat],
animations: {
// Suas animações
}, completion: nil)
Poderemos passar o delay (tempo que a animação vai demorar até começar), poderemos passar um array do tipo UIView.AnimationOptions, que deixa escolher uma curva personalizada, por exemplo. Podemos passar também um callback para quando a animação terminar.
Exemplos reais com UIView.animate
Animações com UIViewPropertyAnimator
Implementação básica
Outro modo de aplicarmos animações em nossos objetos é utilizando o UIViewPropertyAnimator. Veja a implementação básica:
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeIn) {
// Sua animação
}
Bem parecido com UIView.animate, né? Mas só isso não basta para nossa animação funcionar, precisamos também de algo para dar inicializar ela, algo como um .start() ou coisas parecidas.
Entendendo o UIViewAnimating Protocol
Para entendermos como o UIViewPropertyAnimator funciona, precisamos ir mais a fundo. Ele conforma com o UIViewAnimating Protocol, que disponibiliza métodos para o controle do fluxo básico de uma animação, como a possibilidade de iniciar, pausar e parar uma animação, além de outras propriedades para ver o estado de uma animação, por exemplo. Veja os métodos desta interface:
func startAnimation()
func pauseAnimation()func stopAnimation(_ withoutFinishing:)func finishAnimation(at finalPosition:)
Agora que entendemos este protocolo, podemos de fato iniciar nossa animação, completando o método mostrado lá atrás.
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeIn) {
// Sua animação
}animator.startAnimation()
Entendendo o UIViewImplicitlyAnimating Protocol
Outro protocolo que o UIViewPropertyAnimator adota é o UIViewImplicitlyAnimating, que nos dispinibiliza métodos para adicionar blocos de animação aos nossos animators sem precisarmos definir as animações no inicio, como no código acima. Veja os métodos deste protocolo:
open func addAnimations(_ animation:)
open func addCompletion(_ completion:)
Com esses métodos, podemos mudar o jeito como criamos o nosso animator:
let animator = UIViewPropertyAnimator(duration: 1, curve: .easeIn)// Poderemos adicionar as animações depois
animator.addAnimations {
// Sua animação
}// Podemos adicionar uma ação quando a animação terminar
animator.addCompletion {
// Callback…
}animator.startAnimation()
Dessa forma você consegue fazer sua incrível animação! Mas, adivinha só… não para por aí! Uma das principais vantagens de utilizar o UIViewPropertyAnimator, além de fazer animações de forma linear (com começo e fim) podemos criar animações interativas e controlar o timing de uma animação nós mesmos!
Exemplos reais utilizando UIViewPropertyAnimator
Existem muitas outras formas nativas de fazer animações, uma delas é utilizando o Core Animation, por exemplo:
CABasicAnimation(keypath:)
Os métodos do CoreAnimation são bem avançados, apesar do nome, e nele podemos mexer com as animações de mais baixo nível, a nível da árvore de layers. Neste artigo não vamos abordar o CA, mas sinta-se livre para pesquisar!
BÔNUS: Algumas bibliotecas para animação
Agora que vimos a forma nativa de implementar animações, vamos ver algumas das melhores bibliotecas utilizadas atualmente.
Lottie
Criado pelo time de engenharia da AirBnb, Lottie é uma biblioteca poderosa para colocar animações vetorizadas de forma simples no nosso aplicativo.
Processo de criação e desenvolvimento de uma animação
- Precisaremos das imagens que vamos animar, para isso podemos utilizar o Adobe Illustrator ou o Sketch. A própria documentação nos diz que é preciso utilizar o arquivo .ai (arquivo nativo do Illustrator) então para a utilização do Sketch pode-se utilizar o plugin SketchToAI. Veja mais na documentação.
- Já no After Effects, onde de fato faremos nossa animação, precisaremos exporta-la para JSON. É assim que o Lottie funciona. O plugin Bodymovin sempre foi utilizado para exportar, porém recentemente foi lançado o plugin LottieFiles, desenvolvido também pela AirBnb. Uma das principais vantagens é ter acesso a uma biblioteca de animações online contendo diversas animações para você inserir no seu projeto, além de poder visualizar sua animação direto do seu celular.
- Feito a exportação para JSON, vamos adicionar a biblioteca Lottie ao nosso app, disponível para iOS em Carthage e Cocoapods, Android, React Native e outras.
pod 'lottie-ios'
Não sei fazer animações, e agora?
Não se preocupe! Lottie possui uma comunidade gigante de designers produzindo animações, e você pode acessa-las e fazer o download de forma gratuita aqui: LottieFiles.
Quero mudar a cor de uma animação que eu baixei, como faço?
LottieEditor permite que você edite as cores das animações que baixou no LottieFiles de forma simples e fácil, basta acessar o site, importar a animação baixada e editar as camadas que deseja.
NOVIDADE: Sobre o dotLottie
dotLottie (.lottie) é um formato recém lançado pela AirBnb que possibilita ter, além de uma fácil identificação do formato do arquivo (Lottie sempre fez uso de JSON como “arquivo Lottie” e agora tem seu próprio formato!) tem também a possibilidade de colocar várias animações dentro de um arquivo .lottie só, contendo um manifesto com informações de versão, arquivos de animação, imagens para prévia das animações e um roadmap incrível com a possibilidade futura de conter vídeos e áudios futuramente!
Vale a pena ficar por dentro da documentação: https://dotlottie.io/intro/
Exemplos reais com Lottie
Hero Transitions
É uma biblioteca para transições animadas entre view controllers muito utilizada em vários projetos. Ela é similar com o Magic Move do Keynote, da Apple. Através de um ID único definido por você em uma view, por exemplo, ao colocar este mesmo ID em outro objeto, em outra view controller, a biblioteca irá associar e fará a transição de forma suave entre o tamanho e cores destes objetos.
Github e documentação: https://github.com/HeroTransitions/Hero
Para implementar, adicione a biblioteca ao seu projeto e importe onde for usar:
pod 'Hero' // Instalação através do Cocoapodsimport Hero // Importe a biblioteca onde for utilizar
Utilize o código abaixo para animar uma view customizada, por exemplo:
// Na sua ViewController1
customView.hero.id = "id_exemplo"
navigationController?.present(vc2, animated: true, completion: nil)// Na sua ViewController2
isHeroEnabled = true
customBackgroundView.hero.id = "id_exemplo"
Repare que nas duas ViewController’s utilizamos o mesmo ID em views diferentes. Dessa forma, ao fazer a navegação para a outra ViewController, o nosso customView irá transicionar de forma suave para o nosso objeto customBackgroundView.
Exemplo real do Hero
Para mais exemplos, veja a galeria oficial deles aqui.
Skeleton View
Para finalizarmos com chave de ouro vou recomendar uma biblioteca que considero incrível. SkeletonView é interessante ao fazer request e já preparar o usuário para o tipo de conteúdo que ele receberá na resposta. Está disponível no Carthage e Cocoapods.
Veja a documentação no git: https://github.com/Juanpe/SkeletonView
Para começar a utilizar, adicione a biblioteca ao seu projeto e importe onde quiser usar:
pod 'SkeletonView'// Não se esqueça de importar!
import SkeletonView
Após fazer isso, é só adicionar a sua view e iniciar a animação! Existem vários métodos e estilos diferentes de personalização, todos estão disponíveis no github acima. Veja um exemplo:
// 1 - Faça com que o objeto possa ser "skeletonável"
imageView.isSkeletonable = true
descriptionLabel.isSkeletonable = true// 2 - Vamos adicionar bordas arredondadas na imagem e em cada linha do nosso texto
imageView.skeletonCornerRadius = 16
descriptionLabel.linesCornerRadius = 6// 3 - Aplique a animação
imageView.showAnimatedGradientSkeleton()
descriptionLabel.showAnimatedGradientSkeleton()// 4 - Quando quiser remover
imageView.hideSkeleton()
descriptionLabel.hideSkeleton()
Nosso resultado final utilizando o código acima ficará assim:
Com o SkeletonView podemos fazer ainda mais do que o básico! Podemos alterar as cores, estilo da animação e direção em que a animação acontece. Além disso, conseguimos também aplicar em listas e muito mais! Deem uma olhada na documentação dessa incrível biblioteca.
Designer, vamos colocar em prática?
- Não pensem em interfaces como elementos estáticos, pensem sempre como elementos fluídos de expressão;
- Considere animações ou a possibilidade delas logo no inicio do protótipo;
- Conversem com os desenvolvedores.
Devs, vamos colocar em prática?
- Utilizem as dicas deste artigo para criarem os seus próprios componentes. Estimulem a criatividade;
- Mostrem novas possibilidades aos designers, por exemplo, utilização do 3D Touch, haptic, gestos, componentes nativos;
- Pesquisem, sempre, se é possível fazer algo antes de dizer que não;
- Conversem com os designers.
Isso é tudo, pe-pe-pessoal!
Espero que tenham gostado, não se esqueçam de aplaudir. Foquem em criar aplicativos com a melhor experiência possível e façam uso de animações da maneira correta. Qualquer dúvida, me contatem no LinkedIn. Abraços, até logo!
Baixe o projeto!
Todos os exemplos feitos por mim utilizados acima podem ser encontrados no projeto abaixo caso você queira consultar exemplo de código! Está disponível no meu github: https://github.com/leocoout/Animations
Entre em contato comigo:
- LinkedIn: https://www.linkedin.com/in/leocout/
- Twitter: https://twitter.com/LeocooutBR
Artigos mencionados:
- Fiz várias referências sobre este artigo… recomendo de verdade a leitura. Animação tradicional vs UI Motion: https://medium.com/uxmotiondesign/o-motion-na-interface-vs-o-motion-tradicional-2e39c92056bc
- Princípios do UX em UI Motion: https://medium.com/ux-in-motion/creating-usability-with-motion-the-ux-in-motion-manifesto-a87a4584ddc