A unified Jetpack Compose component for playing SVGA, PAG, and VAP animations with a single API — auto format detection, lifecycle-aware playback, off-screen auto-pause, dynamic text/image injection, and external controllers.
- One API, three formats —
SVGA/PAG/VAP, auto-detected from file suffix (.svga,.pag,.vap,.mp4). - Multiple sources — URL (with download + disk cache), local
File, orassets/path. - Lifecycle-aware — automatically pauses on host
onStop, resumes ononStart. - Off-screen auto-pause — animations scrolled out of a
LazyColumnviewport stop rendering to save GPU/decoder work. - Dynamic resources — inject runtime text and images into SVGA/VAP templates.
- External control —
AnimationControllerwith observableplayState. - Event callbacks —
Started,Paused,Resumed,Repeated,Completed,Failed.
The library depends on three third-party animation SDKs; SVGAPlayer-Android is hosted on JitPack, so add the repository first.
settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}Then add the module (or copy the animation/ module into your project):
// your-app/build.gradle.kts
dependencies {
implementation(project(":animation"))
}Requirements: minSdk 26, Kotlin 2.3+, AGP 8.13+, Jetpack Compose.
// Simplest case — just a URL
AnimationPlayer(url = "https://cdn.example.com/gift.svga")
// Full API
AnimationPlayer(
source = AnimationSource.Url("https://cdn.example.com/effect.pag"),
modifier = Modifier.size(200.dp),
config = AnimationConfig(repeatMode = RepeatMode.Once),
onEvent = { event ->
if (event is AnimationEvent.Failed) Log.e("App", event.message, event.cause)
},
)
// Local asset
AnimationPlayer(assetPath = "animations/welcome.svga")
// Local file
AnimationPlayer(file = File(cacheDir, "effect.pag"))val controller = rememberAnimationController()
AnimationPlayer(
source = AnimationSource.Asset("animations/welcome.svga"),
controller = controller,
config = AnimationConfig(autoPlay = false),
)
Row {
Button(onClick = controller::play) { Text("Play") }
Button(onClick = controller::pause) { Text("Pause") }
Button(onClick = controller::stop) { Text("Stop") }
}
// Observe state
val state by controller.playState.collectAsState()Note: VAP
pause()is not a true pause — it stops playback, andplay()restarts from frame 0.
val resource = remember(userId, name) {
dynamicResource {
text("username", name)
image("avatar", avatarBitmap)
}
}
AnimationPlayer(
url = "https://cdn.example.com/gift.svga",
dynamicResource = resource,
)Wrap construction in remember { ... } — DynamicResource identity is used as the reload key.
AnimationConfig(
repeatMode = RepeatMode.Infinite, // Once | Infinite | Times(n)
autoPlay = true,
scaleType = AnimationScaleType.FitCenter,
)| Format | Extension | SDK |
|---|---|---|
| SVGA | .svga |
com.github.qqnp1100:SVGAPlayer-Android |
| PAG | .pag |
com.tencent.tav:libpag |
| VAP | .vap / .mp4 |
io.github.tencent:vap |
:animation— the reusable library module (packagecom.tongsr.animation).:app— a minimal demo host.
MIT. Third-party animation SDKs retain their own licenses.
一个统一的 Jetpack Compose 动画播放组件,单一 API 同时支持 SVGA / PAG / VAP 三种格式 —— 自动识别格式、感知生命周期、离屏自动暂停、动态文本/图片替换、外部控制器。
- 一个 API,三种格式 —— 根据文件后缀 (
.svga、.pag、.vap、.mp4) 自动选择解码器。 - 多种数据源 —— URL(内置下载 + 磁盘缓存)、本地
File、assets/路径。 - 生命周期感知 —— 宿主
onStop自动暂停,onStart自动恢复。 - 离屏自动暂停 ——
LazyColumn中滑出视口的动画自动停止解码,节省 GPU。 - 动态资源替换 —— SVGA / VAP 模板可在运行时注入文字和图片。
- 外部控制 —— 提供
AnimationController并暴露可观察的playState。 - 事件回调 ——
Started/Paused/Resumed/Repeated/Completed/Failed。
库依赖三个第三方动画 SDK,其中 SVGAPlayer-Android 发布在 JitPack,需要先添加仓库:
settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}然后引入模块(或将 animation/ 模块复制到你的工程):
// your-app/build.gradle.kts
dependencies {
implementation(project(":animation"))
}环境要求: minSdk 26、Kotlin 2.3+、AGP 8.13+、Jetpack Compose。
// 最简用法 —— 一个 URL 即可
AnimationPlayer(url = "https://cdn.example.com/gift.svga")
// 完整 API
AnimationPlayer(
source = AnimationSource.Url("https://cdn.example.com/effect.pag"),
modifier = Modifier.size(200.dp),
config = AnimationConfig(repeatMode = RepeatMode.Once),
onEvent = { event ->
if (event is AnimationEvent.Failed) Log.e("App", event.message, event.cause)
},
)
// 本地 assets
AnimationPlayer(assetPath = "animations/welcome.svga")
// 本地文件
AnimationPlayer(file = File(cacheDir, "effect.pag"))val controller = rememberAnimationController()
AnimationPlayer(
source = AnimationSource.Asset("animations/welcome.svga"),
controller = controller,
config = AnimationConfig(autoPlay = false),
)
Row {
Button(onClick = controller::play) { Text("播放") }
Button(onClick = controller::pause) { Text("暂停") }
Button(onClick = controller::stop) { Text("停止") }
}
// 观察状态
val state by controller.playState.collectAsState()注意: VAP 的
pause()并非真正的暂停 —— 它会停止播放,随后的play()会从第 0 帧重新开始。
val resource = remember(userId, name) {
dynamicResource {
text("username", name)
image("avatar", avatarBitmap)
}
}
AnimationPlayer(
url = "https://cdn.example.com/gift.svga",
dynamicResource = resource,
)请务必在 remember { ... } 中构建 —— DynamicResource 的对象身份会作为重载 key。
AnimationConfig(
repeatMode = RepeatMode.Infinite, // Once | Infinite | Times(n)
autoPlay = true,
scaleType = AnimationScaleType.FitCenter,
)| 格式 | 后缀 | SDK |
|---|---|---|
| SVGA | .svga |
com.github.qqnp1100:SVGAPlayer-Android |
| PAG | .pag |
com.tencent.tav:libpag |
| VAP | .vap / .mp4 |
io.github.tencent:vap |
:animation—— 可复用的组件模块(包名com.tongsr.animation)。:app—— 最小化的 Demo 宿主。
MIT。三个第三方动画 SDK 遵循各自的许可协议。