如何暂停/恢复Jetpack Compose虚线边框的无限过渡动画?
解决Jetpack Compose虚线边框动画切换跳变问题
问题场景
在Android应用中通过自定义Modifier绘制虚线边框,需求是视图选中时播放虚线动画,未选中时暂停动画(保持当前位置)。使用InfiniteTransition实现后,切换动画状态时出现明显跳变(动画状态切换时虚线直接跳回初始位置),需要优化实现方式避免跳变。
问题根源
当前代码在animate为false时直接将dashPathEffect的phase设为0f,导致动画状态切换时,虚线偏移量从当前动画值突然跳转到0,产生视觉跳变。且InfiniteTransition没有直接的暂停API,无法直接暂停动画并保留当前进度。
解决方案
放弃InfiniteTransition,改用手动维护偏移量状态结合协程的方式控制动画:
- 用状态变量保存当前的虚线偏移值
- 当
animate为true时,通过LaunchedEffect启动协程,持续更新偏移量实现无限动画 - 当
animate为false时,停止协程,保留当前偏移量,避免跳变
优化后完整代码
fun Modifier.dashedBorder( color: Color, strokeWidth: Dp, strokeLength: Dp, animate: Boolean = false, ) = composed( factory = { val density = LocalDensity.current val strokeWidthPx = density.run { strokeWidth.toPx() } val strokeLengthPx = density.run { strokeLength.toPx() } val dashCycleLength = strokeLengthPx * 2 // 虚线+间隔的总长度 // 保存当前虚线偏移量的状态 val currentOffset = remember { mutableStateOf(0f) } LaunchedEffect(animate) { if (animate) { // 动画播放时,持续更新偏移量 while (true) { // 计算下一帧的偏移值,循环回到0 currentOffset.value = (currentOffset.value + 2f) % dashCycleLength delay(16) // 近似60fps的帧间隔 } } // animate为false时,协程自动取消,停止更新偏移量 } this.then( Modifier.drawWithCache { onDrawBehind { val stroke = Stroke( width = strokeWidthPx, pathEffect = PathEffect.dashPathEffect( intervals = floatArrayOf(strokeLengthPx, strokeLengthPx), phase = currentOffset.value // 始终使用当前偏移量,无跳变 ) ) drawRect( color = color, style = stroke, ) } } ) } )
补充说明
- 协程中
delay(16)模拟60fps动画帧率,可通过调整步长(+2f)和延迟时间控制动画速度 - 切换到非动画状态时,协程自动取消,
currentOffset保留最后偏移值,虚线停在当前位置无跳变 - 偏移量超过
dashCycleLength后重置为0,实现无限循环的滚动效果
内容的提问来源于stack exchange,提问作者m.reiter
相关产品推荐
相关产品推荐

