如何让Compose动画在每次点击触发时强制重置?
问题解决:强制每次点击重启闪行动画
问题原因
当前实现中,快速点击时旧的延迟协程仍在运行,会在500ms后强制将状态设为false;同时AnimatedVisibility的过渡状态未被重置,导致无法重新触发进入动画,只能继续执行退出动画。
解决方案
通过取消旧任务+强制重置动画组件的方式,确保每次点击都启动全新的动画周期:
1. 修改状态管理类
在DefaultFlashBoxState中保存并取消旧的延迟任务,同时新增计数器用于重置动画组件:
interface FlashBoxState { val isVisible: MutableTransitionState<Boolean> val flashCount: State<Int> fun flash() } private class DefaultFlashBoxState( private val coroutineScope: CoroutineScope, ) : FlashBoxState { override val isVisible = MutableTransitionState(false) private val _flashCount = mutableStateOf(0) override val flashCount: State<Int> = _flashCount private var flashJob: Job? = null override fun flash() { // 取消之前未完成的延迟任务 flashJob?.cancel() // 递增计数器,触发动画组件重建 _flashCount.value++ // 启动新的显示动画 isVisible.targetState = true // 启动新的延迟隐藏任务 flashJob = coroutineScope.launch { delay(500) isVisible.targetState = false } } } @Composable fun rememberFlashBoxState(): FlashBoxState { val coroutineScope = rememberCoroutineScope() return remember { DefaultFlashBoxState(coroutineScope) } }
2. 重置动画组件
在FlashBox的AnimatedVisibility中添加key参数,使用计数器强制每次点击重建动画:
@Composable fun FlashBox( state: FlashBoxState, content: @Composable () -> Unit ) { Box { content() Column(modifier = Modifier.align(Alignment.BottomCenter)) { AnimatedVisibility( key = state.flashCount.value, // 新增key,强制重建动画 visibleState = state.isVisible, enter = fadeIn(animationSpec = tween(durationMillis = 200)) + slideIn( animationSpec = tween(durationMillis = 200), initialOffset = { size -> IntOffset(0, y = size.height) } ), exit = fadeOut(animationSpec = tween(durationMillis = 1000)) + slideOut( animationSpec = tween(durationMillis = 1000), targetOffset = { size -> IntOffset(x = 0, y = size.height * (-6)) }, ), ) { Text(text = "Copied!", textAlign = TextAlign.Center, modifier = Modifier.width(150.dp)) } } } }
更直观的简化实现
可以去掉单独的状态类,直接在FlashBox内部处理状态逻辑,代码更简洁:
@Composable fun FlashBox( content: @Composable (onFlash: () -> Unit) -> Unit ) { var showFlash by remember { mutableStateOf(false) } var flashTrigger by remember { mutableStateOf(0) } Box { // 给子组件传递触发动画的函数 content { flashTrigger++ showFlash = true } Column(modifier = Modifier.align(Alignment.BottomCenter)) { AnimatedVisibility( key = flashTrigger, visible = showFlash, enter = fadeIn(tween(200)) + slideIn(tween(200)) { IntOffset(0, it.height) }, exit = fadeOut(tween(1000)) + slideOut(tween(1000)) { IntOffset(0, -it.height * 6) } ) { Text( text = "Copied!", textAlign = TextAlign.Center, modifier = Modifier.width(150.dp) ) } } } // 自动延迟隐藏 LaunchedEffect(flashTrigger) { delay(500) showFlash = false } } // 使用方式 FlashBox { onFlash -> CodePointCell( size = 150.dp, onClick = onFlash ) }
内容的提问来源于stack exchange,提问作者Hakanai
相关产品推荐
相关产品推荐

