Lottie:把动画制作甩给 UI 设计师

851 阅读2分钟

我正在参加「掘金·启航计划」

Lottie 是什么

Lottie 是 Airbnb 开源的一个动画库,它支持 Android,iOS,React Native,Web,Windows,利用 json 文件的方式快速实现动画效果,所以,如果有复杂的动画,可以直接让设计出相关的动画 json 文件,可以大大减轻我们开发的工作量,这个只需设计师用 AE 设计动画,利用 bodymovin 导出,我们坐等动画 json 文件就行啦!

lottie 的项目地址:github.com/airbnb/lott…

加载动画

通过 assets 加载

添加依赖

implementation "com.airbnb.android:lottie:6.0.0"

将 UI 给你的 json 文件放到 app/src/main/assets 目录中

image.png

然后在 XML 中使用 LottieAnimationView 加载即可

<com.airbnb.lottie.LottieAnimationView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:lottie_autoPlay="true"
    app:lottie_fileName="lottie_ani.json"
    app:lottie_loop="true" />

我这个动画的 json 文件是在 lottie 官网下载的,传送门:lottiefiles.com/ ,效果如下:

录屏_选择区域_20230515114505.gif

也可以在代码中动态设置动画

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        tools:context=".MainActivity">

        <com.airbnb.lottie.LottieAnimationView
            android:id="@+id/lottieAnimationView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>
</layout>
binding.lottieAnimationView.apply {
    setAnimation("lottie_ani.json")
    repeatCount = LottieDrawable.INFINITE
    playAnimation()
}

也可以使用 LottieCompositionFactory 加载

LottieCompositionFactory.fromAsset(this, "lottie_ani.json").addListener {
    binding.lottieAnimationView.run {
        setComposition(it)
        repeatCount = LottieDrawable.INFINITE
        playAnimation()
    }
}

如果 Lottie 中有图片,只能通过下面这种方式加载,需要设置 imageAssetsFolder,程序会去 assets 目录下查找。这里指定的路径是 images/,则会去 assets/images/ 路径下寻找。

binding.lottieAnimationView.apply {
    imageAssetsFolder = "images/lottie_img"
    setAnimation("lottie_ani.json")
    // 设置重复次数
    repeatCount = LottieDrawable.INFINITE
    playAnimation()
}

通过 URL 加载

这个网络链接的来源也是 Lottie 官网

binding.lottieAnimationView.apply {
    setAnimationFromUrl("https://assets4.lottiefiles.com/packages/lf20_tSMENoX43Y.json")
    repeatCount = LottieDrawable.INFINITE
    playAnimation()
}
LottieCompositionFactory.fromUrl(
    this, "https://assets4.lottiefiles.com/packages/lf20_tSMENoX43Y.json"
).addListener {
    binding.lottieAnimationView.run {
        setComposition(it)
        repeatCount = LottieDrawable.INFINITE
        playAnimation()
    }
}

效果如下:

录屏_选择区域_20230515145257.gif

通过 raw 加载

我们也可以将本地的 json 文件放到 raw 目录下,raw 加载的功能比 assets 强大,支持 zip 包和 json 文件。

现在从官网里下载一个 zip 包,下载后解压就能看到一个 zip 包。

image.png

把它放入 raw 目录下

image.png

同样,有两种加载方式

binding.lottieAnimationView.apply {
    setAnimation(R.raw.grass)
    repeatCount = LottieDrawable.INFINITE
    playAnimation()
}
LottieCompositionFactory.fromRawRes(this, R.raw.grass).addListener {
    binding.lottieAnimationView.run {
        setComposition(it)
        repeatCount = LottieDrawable.INFINITE
        playAnimation()
    }
}

录屏_选择区域_20230515151507.gif

通过本地文件加载

binding.lottieAnimationView.apply {
    try {
        setAnimation(FileInputStream("${getExternalFilesDir(null)}/robot_ani.json"), null)
        repeatCount = LottieDrawable.INFINITE
        playAnimation()
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
    }
}
LottieCompositionFactory.fromJsonInputStream(
    FileInputStream("${getExternalFilesDir(null)}/robot_ani.json"), null
).addListener {
    binding.lottieAnimationView.run {
        setComposition(it)
        repeatCount = LottieDrawable.INFINITE
        playAnimation()
    }
}

录屏_选择区域_20230515170104.gif

这里顺便总结一下 Android 的文件路径:

  • context.filesDir:对应的路径为 /data/user/0/package_name/files
  • context.cacheDir:对应的路径为 /data/user/0/package_name/cache
  • context.externalCacheDir:对应的路径为 /storage/emulated/0/Android/data/package_name/cache
  • context.getExternalFilesDir(type):对应的路径为 /storage/emulated/0/Android/data/package_name/files
  • Environment.getExternalStorageDirectory():对应的路径为 /storage/emulated/0
  • Environment.DIRECTORY_DOWNLOADS:对应的路径为 /storage/emulated/0/Download

动画控制

播放,取消,继续,暂停

// 播放
binding.lottieAnimationView.playAnimation()
// 取消
binding.lottieAnimationView.cancelAnimation()
// 继续
binding.lottieAnimationView.resumeAnimation()
// 暂停
binding.lottieAnimationView.pauseAnimation()

重复模式

binding.lottieAnimationView.repeatMode = LottieDrawable.RESTART //重新开始
binding.lottieAnimationView.repeatMode = LottieDrawable.REVERSE //反向

动画监听

binding.lottieAnimationView.addAnimatorListener(object : Animator.AnimatorListener {
    override fun onAnimationStart(animation: Animator) {
        // 动画开始时
    }

    override fun onAnimationEnd(animation: Animator) {
        // 动画结束时
    }

    override fun onAnimationCancel(animation: Animator) {
        // 动画取消时
    }

    override fun onAnimationRepeat(animation: Animator) {
        // 动画重复时
    }

})

如果你不想重写这么多的方法,也可以使用 AnimatorListenerAdapter,只需重写我们需要的即可。

binding.lottieAnimationView.addAnimatorListener(object : AnimatorListenerAdapter() {
    override fun onAnimationStart(animation: Animator) {
        // 动画开始时
    }

    override fun onAnimationEnd(animation: Animator) {
        // 动画结束时
    }
})

播放速度

默认为1,也可设置成小数。

binding.lottieAnimationView.speed = 0.5f

获取和设置帧

// 获取帧
val currentFrame = binding.lottieAnimationView.frame
// 设置帧
binding.lottieAnimationView.frame = 30