Jetpack Compose中AnimationDrawable的替代方案是什么?如何实现逐帧动画
Jetpack Compose 逐帧动画实现方案
方案1:复用原有 AnimationDrawable 实现
适合从View体系迁移、已经有成熟逐帧动画xml资源的场景,不需要修改原有资源即可快速接入。
实现步骤:
- 先在
res/drawable目录下定义原有逐帧动画xml文件(示例名为frame_anim.xml) - 用Compose提供的
AndroidView组件包裹ImageView加载动画资源,示例代码如下:
AndroidView( factory = { context -> ImageView(context).apply { // 加载逐帧动画资源 setImageResource(R.drawable.frame_anim) val animDrawable = drawable as AnimationDrawable // 设置是否只播放一次,false为循环播放 animDrawable.isOneShot = false // 组件挂载时启动动画 doOnAttach { animDrawable.start() } // 组件卸载时停止动画,避免内存泄漏 doOnDetach { animDrawable.stop() } } }, modifier = Modifier.size(200.dp) // 按需设置动画尺寸 )
如果需要动态构建逐帧动画,也可以直接在代码中创建AnimationDrawable实例,调用addFrame(Drawable frame, int duration)方法添加帧即可,无需提前定义xml资源。
方案2:Compose 原生声明式实现
推荐纯Compose项目使用,不依赖Android View体系,性能更优,可定制化程度更高。
实现思路是通过状态控制当前显示的帧资源,配合协程定时切换帧,示例代码如下:
@Composable fun FrameAnimation( // 帧资源列表 frameList: List<Int>, // 每帧停留时长,单位毫秒 frameDuration: Int = 100, // 是否循环播放 isRepeat: Boolean = true, modifier: Modifier = Modifier ) { var currentFrameIndex by remember { mutableIntStateOf(0) } var isPlaying by remember { mutableStateOf(true) } LaunchedEffect(isPlaying, currentFrameIndex) { if (!isPlaying) return@LaunchedEffect // 等待当前帧播放时长 delay(frameDuration.toLong()) val nextIndex = currentFrameIndex + 1 currentFrameIndex = when { nextIndex < frameList.size -> nextIndex isRepeat -> 0 else -> { // 播放到最后一帧,停止动画 isPlaying = false currentFrameIndex } } } Image( painter = painterResource(id = frameList[currentFrameIndex]), contentDescription = null, modifier = modifier ) }
使用时直接传入帧资源即可:
FrameAnimation( frameList = listOf(R.drawable.frame1, R.drawable.frame2, R.drawable.frame3, R.drawable.frame4), frameDuration = 120, modifier = Modifier.size(200.dp) )
该方案可以自由扩展暂停、继续、倒放、倍速、指定起始帧等自定义能力,适配更复杂的动画需求。
内容的提问来源于stack exchange,提问作者Ali Jawad Hussain Gorayya
相关产品推荐
相关产品推荐

