Android 动效方案探索
前言
我们知道在 Android 中实现动画效果,可以通过补间动画、帧动画和属性动画。对于一些简单的动画效果,用上述方式实现没啥问题。但是对于复杂的动画,无论从动态效果展示和动画资源大小,还是支持动态更新,上述三种方式都无法完全满足这种需求。这时候就需要重新考虑实现方式了,下面介绍两种市面上比较常见的动效播放 SDK,主要从如何接入和 UI 动效两方面进行介绍。
开始
PAG
PAG(Portable Animated Graphics)是腾讯出品的一套完整动效解决方案,目标是降低或消除动效相关的研发成本,能够一键将设计师在 AE(Adobe After Effects)中制作的动效内容导出成素材文件,并快速上线应用于几乎所有的主流平台。
其中提供社区版和企业版版本供大家选择,其中企业版又提供大杯、中杯、小杯三种选择。社区版只提供基础能力,支持 2D 效果的动效展示。社区版同时支持视频和音频播放、3D 动效的展示,并且支持在线动效资源动态替换。
PAG 优势
高效的动效文件
- PAG 动效文件采用了二进制的数据结构来存储AE动效信息,这使得它能够非常方便地单文件集成任何资源,如位图、音频、视频资源等,实现单文件交付。
- 二进制数据结构不需要像 JSON 一样处理字符串匹配问题,解码速度可以快 90% 以上。
- 在压缩率方面,相比 JSON,二进制数据结构可以跳过 Key 的内容,只存储 Value,这样能节省大量空间。
- 经过一系列的压缩策略,导出相同的AE动效内容,PAG 在文件解码速度和压缩率上均大幅领先于同类型方案。
广泛的平台支持
- PAG 支持 Android、iOS、Web、macOS、Windows、Linux 和微信小程序等平台,为开发者提供了跨平台的一致性体验。
高性能的渲染
- PAG 的渲染主体通过跨平台的 C++ 来实现,所有平台均一致开启 GPU 硬件加速,确保各平台测的渲染一致性。
- 高效的动效文件和优化的渲染引擎使得 PAG 在性能上表现出色,能够轻松应对复杂场景下的动效渲染需求。
丰富的应用场景
- PAG 可以应用于照片模板、视频模板、智能剪辑等多种场景,满足设计师和开发者在不同业务场景下的需求。
PAG 集成
aar 集成
- 将 libpag 的 aar 文件放置在 android 工程项目的 libs 目录下。
- 添加 aar 库依赖,在 app 的 gradle 文件 app/build.gradle,添加 libpag 的库依赖。
android {
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
//libpag 的核心库
//将 libpag_enterprise_4.2.41_android_armeabi_armv7a_arm64v8a.aar 换成你下载的 aar 文件名
implementation(name: 'libpag_enterprise_4.2.41_android_armeabi_armv7a_arm64v8a.aar', ext: 'aar')
implementation("androidx.exifinterface:exifinterface:1.3.3")
}
注意: 需要在混淆列表里面,添加 libpag 的 keep 规则:
-keep class org.libpag.** {*;}
-keep class androidx.exifinterface.** {*;}
配置完以后,sync 一下,再编译。
Maven 集成
这里介绍一下,PAG 一共提供六个版本(以4.2.41版本为例):
企业基础版本:com.tencent.tav:libpag-enterprise:4.2.41,不包含 Movie 模块,不支持多字节 emoji,包含素材加密和 3D 图层能力。
企业 movie 版本:com.tencent.tav:libpag-enterprise:4.2.41-movie,包含音频播放、素材加密、占位图一键替换视频、导出视频文件和 3D 图层以及多字节 emoji 的能力。
企业 noffavc 版本:com.tencent.tav:libpag-enterprise:4.2.41-noffavc,不包含 Movie 模块和多字节 emoji 能力、内部不包含软件解码器,支持解码器外部注入。
社区基础版本 com.tencent.tav:libpag:4.2.41 不支持多字节 emoji,包含 PAG 的基础能力。
社区 harfbuzz 版本 com.tencent.tav:libpag:4.2.41-harfbuzz 支持多字节 emoji 的能力。
社区 noffavc 版本 com.tencent.tav:libpag:4.2.41-noffavc 不支持多字节 emoji,内部不包含软件解码器,支持解码器外部注入。
- 在 root 工程目录下面修改 build.gradle 文件,增加mavenCentral()
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
- 在 app 的 gradle 文件 app/build.gradle,添加 libpag 的库依赖
dependencies {
//基础版本,如需保持最新版本,可以使用 latest.release 指代
implementation 'com.tencent.tav:libpag:latest.release'
}
注意: 需要在混淆列表里面,添加 libpag 的 keep 规则:
-keep class org.libpag.** {*;}
-keep class androidx.exifinterface.** {*;}
配置完以后,sync 一下,再编译。
示例
代码实现
在 XML 中引入 PAGImageView,然后在代码中设置动画资源并开启播放。
libpag.PAGImageView
android:id="@+id/pagImageView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
class PAGAnimActivity:AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pag_anim)
val pagIv = findViewById<PAGImageView>(R.id.pagImageView)
//设置资源路径
pagIv.setPath("assets://data_video.pag")
//设置重复播放次数
pagIv.setRepeatCount(Int.MAX_VALUE)
//开启播放
pagIv.play()
}
}
UI 动效
Lottie
Lottie 是 Airbnb 开源的一套跨平台的完整动画效果解决方案,是一种基于 JSON 的动画文件格式,可以在任意平台进行动画播放。在不同的设备上,可以放大或缩小而不会出现像素化。在多个平台上无缝运行,大大节省了开发资源。
Lottie 优势
文件小
与 GIF 或 MP4 等其他格式相比,Lottie 动画更小,但质量保持不变。
无限可扩展
Lottie 动画基于矢量,这意味着您可以放大或缩小它们而不必担心分辨率。
多平台支持和库
对于所有开发人员来说,Lottie 的交付非常简单。您可以在 iOS、Android、Web 和 React Native 上使用 Lottie 动画,无需修改。
交互性
在 Lottie 动画中,动画元素是公开的,因此您可以操纵它们进行交互并响应滚动、点击和悬停等交互。在交互指南中了解更多信息。
Lottie 集成
配置 Gradle
dependencies {
implementation "com.airbnb.android:lottie:$lottieVersion"
}
目前最新的版本是 6.6.2,如需获取最新版本请戳这里。
示例
下面用两种实现方式演示 Lottie 播放动画的效果。
Kotlin 实现
首先用代码的方式实现,主要方法也进行了注释。
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val lottieView = findViewById<LottieAnimationView>(R.id.lottieView)
//设置动画资源,资源放在assets目录下,注意这里只设置资源名称即可
lottieView.setAnimation("anim2.json")
//设置动画重复播放次数
lottieView.repeatCount = Int.MAX_VALUE
//播放动画
lottieView.playAnimation()
}
}
XML 实现
首先我们在 XML 布局中引入 LottieAnimationView,通过 lottie_fileName 设置资源文件,并设置无限轮询播放和自动开启播放。
airbnb.lottie.LottieAnimationView
android:id="@+id/lottieView"
android:layout_width="0dp"
android:layout_height="0dp"
app:lottie_fileName="anim2.json"
app:lottie_loop="true"
app:lottie_autoPlay="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
UI 动效
播放的效果如下图所示,动画播放流畅度还是比较丝滑的。
Lottie 详细介绍
动画资源
Lottie 支持以下来源的动画,能满足产品需求。
- 在
src/main/res/raw
目录下,json 格式的动画资源文件。 - 在
src/main/assets
目录中,json/zip/[dotLottie] 格式的动画资源文件。 - 来源于 url/InputStream 的 json 或 zip 动画资源文件 。
- JSON 字符串,来源方式不限。
动画缓存
Lottie 同样也支持动画缓存,通过 LruCache 来实现,支持最大缓存数是20。可以通过 setCacheComposition(boolean cacheComposition) 方法来决定是否开启预缓存。
全局配置
Lottie 支持全局配置,如有以下需求可以进行单独配置,放在Application进行初始化:
- 从网络加载动画时,使用自定义网络请求框架。
- 从网络获取的动画使用自定义缓存目录,摒弃原有的 Lottie 的默认目录 (
cacheDir/lottie_network_cache
)。 - 启用 Systrace 标记以进行调试。
- 自定义网络框架缓存策略,需要关闭 Lottie 的网络缓存。
Lottie.initialize(
LottieConfig.Builder()
.setNetworkFetcher(...)
.setEnableSystraceMarkers(true)
.setNetworkCacheDir(...)
.setEnableNetworkCache(false)
)
动画监听器
Lottie 支持多种动画播放状态的监听,记得注册和解注册成对出现。
lottieView.addAnimatorListener()
lottieView.addAnimatorPauseListener()
lottieView.addAnimatorUpdateListener()
自定义动画效果
通过 Lottie 实现动画基本上满足我们大部分场景需求,当然要是有特殊要求,Lottie 也支持自定义动画效果,下面示例是对动画透明度进行单独设置。
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.addUpdateListener {
lottieView.alpha = animator.animatedValue as Float
}
animator.duration = 3000
animator.start()
Lottie 对 APK 大小有什么影响
非常小:
- 约 1600 种方法。
- 未压缩时为 287kb。
Lottie 的优点
- 支持更多 After Effects 功能。请参阅支持的功能以获取完整列表。
- 手动设置进度以将动画连接到手势、事件等。
- 支持网络下载动画资源。
- 可以动态改变播放速度。
- 图像支持抗锯齿。
- 动态改变动画特定部分的颜色
Lottie 的缺点
Lottie 是为矢量形状而设计的,虽然 Lottie 支持渲染图像,但使用它们也有一些缺点:
- 相同的动画效果,Lottie 使用的文件大小要比等效的矢量动画要大一个数量级。
- 当 Lottie 缩放时,动画会变得像素化。
- 用 Lottie 增加了动画的复杂性,动画资源不仅仅是一个文件,而是 json 文件加上所有图像。
DotLottie
DotLottie是一个新的 Lottie 播放器,依靠 ThorVG 进行渲染,其通过新的 dotLottie Runtimes 实现跨平台支持,拥有更快的加载速度,同时还能保证不同平台的动画一致性和高性能的表现。
DotLottie 优势
- 动画文件小:高达 80% 动画压缩,且在放大或缩小而不会出现像素化。
- 自适应主题:支持昼夜主题模式,或者自定义模式
- 支持动画资源包:资源包中的 dotLottie 文件中包含多个动画,简化动画的管理和部署。
- 高性能:dotLottie 图形处理由高性能图形引擎 ThorVG 提供支持,支持比普通 JSON 小 80% 的 dotLottie 格式。
DotLottie 集成
配置 Gradle
repositories {
maven(url = "https://jitpack.io")
}
dependencies {
implementation("com.github.LottieFiles:dotlottie-android:0.5.0")
}
示例
下面用两种实现方式演示 DotLottie 播放动画的效果。
Kotlin 实现
首先在 XML 布局中引入 DotLottieAnimation,然后在代码里面配置相应的 Config,这里 Config 是必须要配置的,否则无法正常播放动画。
lottiefiles.dotlottie.core.widget.DotLottieAnimation
android:id="@+id/dotLottieView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
class DotLottieAnimActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dot_lottie_anim)
val dotLottieView = findViewById<DotLottieAnimation>(R.id.dotLottieView)
val dotConfig = Config.Builder()
.autoplay(true)
.speed(1f)
.loop(true)
// 本地资源,支持.json或.lottie两种格式
// .source(DotLottieSource.Asset("anim.lottie"))
//在线资源
.source(DotLottieSource.Url("https://lottie.host/5525262b-4e57-4f0a-8103-cfdaa7c8969e/VCYIkooYX8.json"))
.playMode(Mode.FORWARD)
.useFrameInterpolation(true)
.build()
dotLottieView.load(dotConfig)
dotLottieView.play()
}
}
UI 动效
Compose 实现
用 Compose 实现相对来说简单许多,只需设置对应的资源文件和播放参数。
@Composable
fun AnimDotLottieView() {
DotLottieAnimation(
source = DotLottieSource.Asset("bicycle.lottie"),
autoplay = true,
loop = true,
speed = 1f,
useFrameInterpolation = true,
playMode = com.dotlottie.dlplayer.Mode.FORWARD
)
}
UI 动效
总结
- Lottie/DotLottie:适用于需要在多种平台上实现一致动画效果的应用场景,采用 JSON 或 Lottie 文件格式。在Android上通过Canvas绘制,并且支持动态更新动画内容。由于其轻量级和高效渲染的特点,即使在低端设备上也能保持流畅的动画效果。
- PAG:广泛应用于腾讯等公司的产品中,涵盖 UI 动画、贴纸动画、照片/视频模板等场景。采用 PAG 二进制文件格式,采用动态比特位压缩技术,所以文件体积小。渲染方式各端共享一套 C++ 实现,平台端只做接口封装,并且支持动态更新动画内容
来源:juejin.cn/post/7452547398670319653