阅读 1682
玩转 Compose 中的 Lottie 动画

玩转 Compose 中的 Lottie 动画

无聊的前言

我太累了,真的太累了,公司项目搞了好久,到现在还一直有问题,导致已经两三个月没有过任何文本输出。其实这都是借口,关键还是变懒了,上周末还出去玩了一趟😂。

Compose 已经发布稳定版几个月了,有个现象我一直很纳闷,在 Compose 发布了 alpha 版本和 beta 版本之后各大技术论坛都开始不停地讨论,并且有相应的一大堆文章输出,但是正式版发布之后反而都销声匿迹了,这是什么情况???

不过这只是技术论坛的一些现状,大佬们还是在不停地前进的,就比如今天的主角——LottieCompose 正式版并没有发布多久就进行了适配。当然目前 Compose 中还是有很多库没有进行适配,不过并不要着急,会很快的,目前适配的大概已经够用了,小部分不能用的也可以通过 AndroidView 进行使用。

正文准备

首先提一个问题,大家一直在使用 Lottie ,那 Lottie 到底是啥呢?来看下官网上的介绍吧:

Lottie 是一个适用于 Android、iOS、Web 和 Windows 的库,它解析使用Bodymovin导出为 json 的Adobe After Effects动画,并在移动设备和 Web 上本地呈现它们!

通过简单的介绍可以知道,如果在 Android 中想要使用 Lottie 播放动画的话,则首先需要一个 json 格式的动画,如果连动画文件都没有你播放个 Der 啊!

那么问题就来了, Lottie 中使用的 json 格式的动画去哪找呢?最简单的办法——找设计要!

什么?设计说不会?出门右转!

算了,给大家安利一个下载 Lottie 中使用的 json 格式动画的网站吧:

lottiefiles.com/

在这个网站中可以进行搜索你想要的动画进行下载,创建个账号就能免费进行下载了,如何下载这里就不贴教程了,大家应该比我会玩。

下载完之后将你下载的文件放到项目的 raw 文件夹下,如果没有 raw 文件夹的话就在 res 文件下创建一个 raw 文件夹,再把下载好的动画文件放进去就可以了。

OK,准备工作完成!

尴尬的正文

上面说了一堆废话,大家不要嫌烦,好久没写文章了,稍微有点陌生。。。现在开始今天的正文。

添加依赖

首先来添加下 Lottie 的依赖吧,在模块的 build.gradle 文件中:

dependencies {
    ...
    implementation "com.airbnb.android:lottie-compose:$lottieVersion"
    ...
}
复制代码

其中的 lottieVersionLottie 的最新版本,在我写这篇文章的时候最新版本为 4.2.0,如果想要使用最新的版本,请将版本号替换为lottieVersion,这就是 Lottie 的最新版本。

由于 Lottie 托管在 Sonatype 仓库中,所以还需要在项目的 build.gradle 文件中添加上 Sonatype 仓库:

allprojects {
    repositories {
        ...
        maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
    }
}
复制代码

到这里为止 Lottie 的依赖就添加完成了,下面开始介绍使用方法吧。

简单使用

先来看下使用代码吧:

@Composable
fun SystemPage() {
    val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.weather_rain))
    val progress by animateLottieCompositionAsState(composition)
    LottieAnimation(composition = composition, progress = progress)
}
复制代码

一共就三行代码,第一行代码将动画文件加载出来,第二行代码将动画文件转为适合 Compose 中使用的 State 文件,第三行将动画文件和 State 文件放入 LottieAnimation 中,嗯,就完成了,这就是 LottieCompose 中的使用方法。

按理说到这里文章就该结束了。(结束啥?你说啥了?就没了?实现出来样式是啥?复杂一点的如何实现?你说了嘛?说了嘛???)

哈哈哈,下面来运行看下效果吧!

lottie1.gif

由于是虚拟机运行的,所以看着有点卡,真机效果非常丝滑,就像德芙一样!

源码解析

上面代码写完之后会发现有些问题,比如咱们想要的可能是不断地循环播放,但是动画之播放一次之后就停止了,和咱们想要的不一样,这种情况该怎么搞?又比如咱们想控制动画的速度该怎么搞?等等,这个时候就需要咱们来看看 Lottie 的源码来寻找答案了!

加载动画文件

首先咱们来看下加载动画文件的方法定义吧:

@Composable
fun rememberLottieComposition(
    spec: LottieCompositionSpec,
    imageAssetsFolder: String? = null,
    fontAssetsFolder: String = "fonts/",
    fontFileExtension: String = ".ttf",
    cacheKey: String? = DefaultCacheKey,
    onRetry: suspend (failCount: Int, previousException: Throwable) -> Boolean = { _, _ -> false },
)
复制代码

可以看到 rememberLottieComposition 函数有六个参数,只有 spec 是必须填写的,剩下的五个参数都是非必需的,下面咱们分别来看下这六个参数都是干嘛用的!

  1. spec:定义应加载哪个 LottieCompositionLottieComposition 就是咱们要加载的动画文件,在下面内容中会展开解释;
  2. imageAssetsFoldersrc/main/assets 中的子文件夹,包含此合成使用的导出图像;
  3. fontAssetsFolderLottie 将在默认文件夹中查找字体文件。字体将根据 Lottie json 文件中指定的系列名称进行匹配,默认值为“fonts”;
  4. fontFileExtension:在 fontAssetsFolderfontRemapping 中指定的字体文件的默认文件扩展名,默认为 ttf;
  5. cacheKey:设置缓存键,设置后的后续调用将直接从缓存返回,而不必重新加载和解析动画,如果将此设置为 null 以跳过缓存。默认情况下,将从 LottieCompositionSpec 自动生成派生的缓存密钥;
  6. onRetry:这是一个挂起函数,如果加载动画失败将调用的可选回调,函数的两个参数分别为传递失败的计数和上一次加载组合的尝试的异常。

通过上面的参数解析我们大概可以知道最常使用的也就是 speconRetry 了,下面先来看看必须参数 spec 的参数类型 LottieCompositionSpec 是个啥吧:

sealed interface LottieCompositionSpec {
​
    /**
     * 从 res/raw 中加载动画
     */
    inline class RawRes(@androidx.annotation.RawRes val resId: Int) : LottieCompositionSpec
​
    /**
     * 从互联网加载动画
     */
    inline class Url(val url: String) : LottieCompositionSpec
​
    /**
     * 从文件中加载动画
     */
    inline class File(val fileName: String) : LottieCompositionSpec
​
    /**
     * 从 Asset 中加载动画
     */
    inline class Asset(val assetName: String) : LottieCompositionSpec
​
    /**
     * 从其 json 字符串加载动画。
     */
    inline class JsonString(val jsonString: String) : LottieCompositionSpec
}
复制代码

通过上面代码可以知道, LottieCompositionSpec 是一个接口,其中有五个类实现了这个接口,可以直接通过构造方法进行调用,加载动画文件的方式很多,即可以加载项目中的动画文件,也可以加载网络文件,还可以加载一个字符串,这大大提高了使用的舒适度,下面来看下使用方式吧!

val composition1 by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.weather_rain))
​
val composition2 by rememberLottieComposition(LottieCompositionSpec.Url("动画文件网址"))
​
val composition3 by rememberLottieComposition(LottieCompositionSpec.File("文件名称"))
​
val composition4 by rememberLottieComposition(LottieCompositionSpec.Asset("文件"))
​
val composition5 by rememberLottieComposition(LottieCompositionSpec.JsonString("动画json文件字符串"))
复制代码

是不是非常简单!

设置动画进度

动画文件创建出来了,下面来看看动画进度的 State 的方法定义吧:

@Composable
fun animateLottieCompositionAsState(
    composition: LottieComposition?,
    isPlaying: Boolean = true,
    restartOnPlay: Boolean = true,
    clipSpec: LottieClipSpec? = null,
    speed: Float = 1f,
    iterations: Int = 1,
    cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediately,
)
复制代码

可以看到,animateLottieCompositionAsState 函数一共有七个参数,其中也是只有一个参数为必须函数,就是咱们刚才创建的 LottieComposition ,剩下的六个参数都是非必需函数,下面还是来具体看下每个参数的用法吧:

  1. isPlaying:表示动画当前是否正在播放。需要注意的是,动画可能会因为达到目标迭代次数而结束,如果发生这种情况,就算将此参数设置为 true 动画也可能会停止;
  2. restartOnPlay:如果 isPlaying 从 false 切换到 true,restartOnPlay 用来确定是否重置进度和迭代;
  3. clipSpec:用于指定动画播放应该被剪辑到的边界(本文不展开介绍此参数);
  4. speed:动画应该播放的速度,大于 1 的话会加快速度, 0 到 1 之间的话会减慢它的速度,小于 0 的话将向后播放;
  5. iterations:动画在停止前应重复的次数(正整数),如果想要永远重复可以设置为 LottieConstants.IterateForeverLottieConstants.IterateForever 其实就是 Integer.MAX_VALUE
  6. cancellationBehavior:动画在取消时的行为,如果有一个基于状态的转换,并希望在继续播放下一个动画之前完成播放,可以设置为 LottieCancellationBehavior.OnIterationFinish

看到这里,其实咱们刚才提出的两个问题都已经解决了,通过设置 speed 就可以修改动画的播放速度,设置 iterations 就可以修改动画的播放次数。来看下使用方式吧:

val progress by animateLottieCompositionAsState(
    composition = composition,
    speed = 2f, // 加快播放速度(2倍速)
    iterations = LottieConstants.IterateForever // 设置永不结束
)
复制代码

在上面代码中我将播放速度设置为了二倍速,并且是永不结束,来看下运行效果吧:

lottie2.gif

可以看到动画速度明显加快,并且会循环播放,已经达到了我们想要的效果。

Lottie动画控件

上面详细说了动画文件的创建和动画进度的设置,下面来看下 Lottie 动画控件 LottieAnimation

@Composable
fun LottieAnimation(
    composition: LottieComposition?,
    @FloatRange(from = 0.0, to = 1.0) progress: Float,
    modifier: Modifier = Modifier,
    outlineMasksAndMattes: Boolean = false,
    applyOpacityToLayers: Boolean = false,
    enableMergePaths: Boolean = false,
    dynamicProperties: LottieDynamicProperties? = null,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
)
复制代码

可以看到 LottieAnimation 一共有九个参数,其中有两个是必须参数,就是上面咱们说过的动画文件和动画进度,剩下的七个为可选参数,咱们来详细看下吧:

  1. modifier:老生常谈的修饰符,可以设置控件的宽高等等,不过多介绍;
  2. outlineMasksAndMattes:启用此选项可通过概述蒙版和遮罩来调试慢速动画,遮罩和遮罩的性能开销将与所有遮罩遮罩组合的表面积成正比,需要注意的是,千万不要在正式版本中启用此功能;
  3. applyOpacityToLayers:设置是否对每个图层而不是形状应用不透明度。不透明度通常直接应用于形状。在半透明形状重叠的情况下,将不透明度应用于图层会更准确,但会牺牲性能;
  4. enableMergePaths:启用实验性合并路径支持,大多数具有合并路径的动画都希望启用此功能,但合并路径支持比其他一些渲染功能更受限制,所以默认为关闭;
  5. dynamicProperties:允许动态更改动画的属性,可以通过rememberLottieDynamicProperties 来使用(本文不再展开描述);
  6. alignment:如果动画的大小与此可组合项的大小不同,则定义应将动画放置在此可组合对象中的位置;
  7. contentScale:如果动画的大小与此此可组合项不同,则定义应如何缩放动画。

大家可以根据实际项目中的需求来选择使用对应的参数。

仓促的结尾

本文其实很简单,只是介绍了 LottieCompose 中的使用方法。

文章如果有什么问题的话请在评论区告诉我。

如果文章对你有帮助别忘了点赞和关注啊。感激不尽🙏。

文章分类
Android