Olá Habr!
Ao mesmo tempo, o Dono do produto nos pediu para pensar em criar um processo eficaz para introduzir animação em nosso aplicativo Android / iOS. Naquele momento, realizamos a tarefa de pré-preencher o aplicativo com dados pessoais para um produto de empréstimo e demorou algum tempo para o servidor responder, durante o qual queríamos mostrar uma bela animação de carregamento.
A tarefa era clara: o designer queria desenhar lindamente, fornecer o código fonte para ambos
plataformas sem dopilivaniya da parte dele, e para que não fique em dispositivos mais antigos (sim, ainda apoiamos o Android 4.1).
Quais foram as minhas opções para a introdução de animação:- Canetas usando desenho animado vetor drawable. O bom é que a renderização funciona
em um thread separado (começando com a api 25), os contras são a complexidade de criar essas animações e um pequeno número de manipulações com objetos. Para animações simples, tudo isso funciona bem, mas um pouco mais complicado, e o inferno começa. Sim, e em plataformas diferentes você não iniciará. - Gif - eles pesam muito, têm um tamanho fixo, o que significa que não escalam normalmente. E você não fará nenhuma manipulação especial com eles.
- A sequência png (sem comentários).
Cavando por algum tempo na direção da animação vetorial nativa do android e gif (oh meu Deus, ainda consideramos essa opção), lembrei-me da maravilhosa biblioteca Lottie e mostrei-a aos meus colegas.
Após alguns testes com vários dispositivos, decidimos que a biblioteca deveria ser implementada, principalmente porque seus recursos eram impressionantes. O designer ficou especialmente satisfeito, agora ele podia fazer quase qualquer animação no Adobe After Effects e exportar para um arquivo json com apenas alguns cliques. Também ficamos encantados, mas primeiro as primeiras coisas.
Lottie foi inventado e implementado pelo Airbnb em resposta a uma demanda crescente por animação entre plataformas, por isso funciona igualmente (bem, quase) em todas as plataformas. Os próprios desenvolvedores afirmam que seu objetivo é obter o número máximo de recursos do After Effects e conseguiram isso. Agora, incorporar animação Lottie é tão fácil quanto inserir uma imagem no ImageView.
Principais 3 classes:- LottieAnimationView é o sucessor do ImageView e a maneira mais fácil de usar animação. Você pode descrever a animação em xml ou no código, a maioria dos métodos é suportada.
- LottieDrawable - o descendente Drawable, com a mesma funcionalidade da classe anterior, permite aplicar animação a qualquer exibição.
- O LottieComposition e seu companheiro LottieCompositionFactory permitem pré-carregar animações de várias fontes e aplicar ao LottieDrawable e LottieAnimationView.
Carregamento de recursos
Oferece suporte ao carregamento de recursos de:
- res / bruto
- src / ativos
- Cadeia Json
- Qualquer URL da rede que leve a um arquivo json ou zip (implementado via HttpURLConnection, para não adicionar dependências externas. Se você tiver animação com imagens, precisará usar o zip)
- Arquivo json ou zip InputStream
Cache de animação
O interessante é que todas as animações baixadas via res / raw ou ativos são salvas pelo cache LRU, o que nos permite não perder tempo do usuário recarregando e analisando a animação, como no caso de animações complexas, pode levar algum tempo. O que é ainda mais interessante: se você precisar pré-carregar a animação e, no próximo fragmento, exibir a animação instantaneamente, poderá usar o código
LottieCompositionFactory.fromRawRes(context, rawFile)
A animação é armazenada em cache usando a chave rawFile e, onde você realmente precisa usá-la, é iniciada quase instantaneamente.
Gerenciamento de progresso
Lottie permite definir o estado atual da animação por meio de setProgress (...). Isso pode ser útil se você deseja animar o status de upload do arquivo, posição de rolagem, vários gestos etc. Vi várias implementações em BottomSheets, PullToRefresh, CollapsingToolbarLayout.
Veja como usar o progresso com o AppBarLayout:
appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val percent = Math.abs(verticalOffset).toFloat()/appBarLayout.totalScrollRange animationView.progress = percent })
Looping
Lottie suporta loop setRepeatMode () ou setRepeatCount () não apenas toda a animação, mas também qualquer fragmento (0,0 ... 1,0). Isso é implementado pelas propriedades setMinFrame, setMaxFrame, setMinAndMaxFrame. Usamos isso para não implementar 3 animações para diferentes estados de upload de arquivos: ocioso, progresso, completo. Aqui está um pequeno pedaço de código que resolve isso:
when (loadingStatus) { LoadingStatus.IDLE -> { animationView.setMaxProgress(0.1f) } LoadingStatus.PROGRESS -> { animationView.setMinAndMaxProgress(0.2f, 0.9f) animationView.repeatCount = LottieDrawable.INFINITE animationView.playAnimation() } LoadingStatus.COMPLETE -> { animationView.setMinAndMaxProgress(0.9f, 1f) animationView.repeatCount = 1 animationView.playAnimation() }}
Imagens
Uma das principais vantagens de Lottie para nós foi que a biblioteca suporta a inserção de imagens diretamente na animação. Além disso, você pode inserir uma imagem estática e uma dinâmica baixada da Internet. Agora vou explicar como isso funciona.
No caso de uma imagem estática, tudo é simples: o designer descarrega o arquivo que contém json mais a própria imagem.
{ "v": "5.1.13", "fr": 29.9700012207031, "ip": 0, "op": 47.0000019143492, "w": 1034, "h": 1334, "nm": " 1", "ddd": 0, "assets": [ { "id": "image_0", "w": 130, "h": 436, "u": "images/", "p": "img_0.png" }, { "id": "comp_0", "layers": [ ... ]}] }
Este img_0.png, esta é a imagem que você deve colocar em src / assets e que estará dentro da animação.
Para carregamento dinâmico, é utilizado o método setImageAssetDelegate, para o qual você deve passar o bitmap. Nós pré-carregamos a imagem com o Glide, então, na fase de abertura de um fragmento com animação e imagem, tudo sai do cache, então tudo é bem rápido. Aqui está o código:
glideLoader.loadAsBitmap(imageUrl).into(object: CustomTarget<Bitmap>() { override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { viewAnimation.setImageAssetDelegate(object: ImageAssetDelegate { override fun fetchBitmap(asset: LottieImageAsset?): Bitmap { asset?.let { val resizeBitmap =Bitmap.createScaledBitmap(resource, it.width, it.height, true); return resizeBitmap } ?: run { return resource } } }) setAnimation(viewAnimation, animationImage) } override fun onLoadCleared(placeholder: Drawable?) {} })
Desempenho
Obviamente, é melhor não usar muita animação em telas nas quais o usuário gasta muito tempo, pois é exigente no processador. De acordo com nossos testes, a carga do processador em algumas animações atinge 20%. Portanto, o caso ideal dessa animação são os elementos interativos que são acionados uma vez.
Se a animação em alguns dispositivos diminui, às vezes ajuda
viewAnimation.useHardwareAcceleration(true)
No entanto, os desenvolvedores recomendam usar esse método com cautela, uma vez que telefones diferentes usam a aceleração de hardware de maneiras diferentes; portanto, em vez de aceleração, você pode obter o efeito oposto.
Conclusão
Em geral, o uso da biblioteca Lottie simplifica bastante a implementação da animação no aplicativo.
As principais vantagens da lottie que destacamos:- Tamanho pequeno da biblioteca (300 kb)
- Solução multiplataforma ios / android / web
- Baixe animações da web
- Gerenciamento de progresso e loop em qualquer lugar
- Um grande número de recursos de efeitos posteriores permite que o designer realize o efeito pretendido.
Contras:- A renderização é feita no encadeamento principal e o fps pode cair significativamente no aplicativo.
- A análise de animações lottie pode levar um tempo considerável com animações complexas.
A propósito, para verificar a intensidade da animação em recursos, você pode usar o aplicativo
Lottie oficial
do Google Play . Há um gráfico de renderização no qual é possível ver o tempo para renderizar um quadro e também como a animação será exibida se você a cortar em quadros, ou como a aceleração por hardware e muito mais afetarão.