Compose 中动态修改 Lottie 动画主题颜色

前言

Lottie 非常方便,因为它能嵌入设计师使用创作工具制作的动画。在 Android 官方(https://developer.android.com)给的 Compose 动画选型流程图中,对于由多个元素构成的复杂插画动画,也建议使用像 Lottie 这样的框架。

在这里插入图片描述

当使用 Lottie 工具制作的动画时,我们有时也希望动态更改其中一部分,比如修改深色/浅色模式,适配夜间主题等。本文将通过示例,介绍如何调整 Lottie 动画内的颜色

示例

首先,准备示例动画。我用 LottieFiles 的 Lottie Creator 制作了一个动画:

在这里插入图片描述

直接播放这个动画,效果如下:

@Composable
fun MyAnimation(modifier: Modifier = Modifier) {
    val composition by rememberLottieComposition(
        spec = LottieCompositionSpec.RawRes(R.raw.my_animation),
    )
    LottieAnimation(
        composition = composition,
        modifier = modifier,
        iterations = LottieConstants.IterateForever,
    )
}

请添加图片描述

修改颜色

假设在这个动画中,想要动态更改勾选标记圆形的背景色。这种情况下,可以使用 Dynamic Property(动态属性)来进行如下指定:

LottieAnimation(
    composition = composition,
    modifier = modifier,
    iterations = LottieConstants.IterateForever,
    dynamicProperties = rememberLottieDynamicProperties(
        rememberLottieDynamicProperty(
            property = LottieProperty.COLOR,
            value = Color.Red.toArgb(),
            keyPath = arrayOf("Icon Asset", "Background", "Background", "Fill"),
        ),
    ),
)

通过这个更改,圆形的颜色变成了红色:

请添加图片描述

关于 Dynamic Property,官方文档中有详细说明:

Lottie 文档:https://airbnb.io

通过 dynamicProperties,使用 KeyPath(关键路径)指定目标对象,然后更改其值,就能动态修改属性。在这次的例子中,指定的 KeyPath 是 Icon Asset > Background > Background > Fill 这个层级。(后面会介绍 KeyPath 的确定方法)

同样地,如果要更改圆周上移动的进度条的颜色,由于它属于描边而不是填充,所以需要将属性类型指定为 LottieProperty.STROKE_COLOR,而不是 LottieProperty.COLOR

rememberLottieDynamicProperty(
    property = LottieProperty.STROKE_COLOR,
    value = Color.Red.toArgb(),
    keyPath = arrayOf("Progress Track", "Stroke"),
),

请添加图片描述

最后,对仍然是蓝色的涟漪也进行同样的指定,就完成了:

dynamicProperties = rememberLottieDynamicProperties(
    rememberLottieDynamicProperty(
        property = LottieProperty.COLOR,
        value = Color.Red.toArgb(),
        keyPath = arrayOf("Icon Asset", "Background", "Background", "Fill"),
    ),
    rememberLottieDynamicProperty(
        property = LottieProperty.STROKE_COLOR,
        value = Color.Red.toArgb(),
        keyPath = arrayOf("Progress Track", "Stroke"),
    ),
    rememberLottieDynamicProperty(
        property = LottieProperty.COLOR,
        value = Color.Red.toArgb(),
        keyPath = arrayOf("Ripple", "Fill"),
    ),
),

请添加图片描述

适配主题

当制定 App 主题时,应当让 Lottie 动画自动适配浅色 / 深色模式

请添加图片描述

dynamicProperties = rememberLottieDynamicProperties(
    rememberLottieDynamicProperty(
        property = LottieProperty.COLOR,
        value = MaterialTheme.colorScheme.primary.toArgb(),
        keyPath = arrayOf("Icon Asset", "Background", "Background", "Fill"),
    ),
    rememberLottieDynamicProperty(
        property = LottieProperty.COLOR,
        value = MaterialTheme.colorScheme.onPrimary.toArgb(),
        keyPath = arrayOf("Icon Asset", "Icon", "Icon", "Fill"),
    ),
    rememberLottieDynamicProperty(
        property = LottieProperty.STROKE_COLOR,
        value = MaterialTheme.colorScheme.primary.toArgb(),
        keyPath = arrayOf("Progress Track", "Stroke"),
    ),
    rememberLottieDynamicProperty(
        property = LottieProperty.COLOR,
        value = MaterialTheme.colorScheme.primary.toArgb(),
        keyPath = arrayOf("Ripple", "Fill"),
    ),
),

值得一提的是,其实 LottieFiles 自带了主题功能,可以在 JSON 中使用在 slot里定义的 token。但是操作下来并没有 Dynamic Property 灵活。

修改 Lottie 动画主题:https://lottiefiles.com/blog/working-with-lottie-animations/how-to-add-themes-to-lottie-animations-in-lottie-creator

确定目标 KeyPath 的方法

现在知道了更改颜色的方法,但关键的 KeyPath 要怎么找呢?这其实挺麻烦的,而且它的结构不一定和创作工具中的图层结构一致,理解起来可能有点困难。

这次用 LottieFiles 制作的动画结构如下,但很难一下子从这里想象出 KeyPath:
在这里插入图片描述

以这次的情况为例进行说明。我们来找找勾选标记背景圆形填充部分的 KeyPath。理论上打开 JSON 文件,顺着 nm 这个键查找肯定能找到,但 lottie 的 json 文件很长,实际找起来比较麻烦。

可以尝试在命令行中使用 jq 列出一些内容,但很难以层级形式展示:

jq '.. | .nm? | strings' my_animation.json

jq 是一个轻量级、高性能的命令行 JSON 处理工具,主要用于在 Unix-like 系统(如 Linux、macOS)中对 JSON 数据进行解析、过滤、转换和格式化等操作。

另外,因为 KeyPath 可以指定通配符,可以通过不断测试,摸清路径,逐步接近目标:

rememberLottieDynamicProperty(
    property = LottieProperty.COLOR,
    value = Color.Red.toArgb(),
    keyPath = arrayOf("Icon Asset", "**", "Fill"),
)

例如,上面代码,通过指定

keyPath = arrayOf("Icon Asset", "**", "Fill"),先大致指定了从 Icon Asset 开始,包含其下所有层级中名为 Fill 的元素,先确认这种宽泛的指定能否实现预期的颜色更改效果,然后再根据实际情况进一步调整 KeyPath,以准确找到需要更改颜色的元素。

还有没有更简便的方法呢? 2025年了,肯定想到借助 AI 了:

AI 提示语:递归扫描 JSON 内的 nm,并基于层级结构显示。

虽然 AI 的准确性并非 100% ,但是即便存在错误,人工也能轻易察觉并进行修正。当然,也可以让 AI 帮忙写一个脚本,通过脚本来查找,往往会更准确。比如下面是我通过 AI 脚本输出的结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fundroid

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值