Jetpack Compose中如何实现极慢的垂直滑出动画
解决方案:实现组件从50dp缓慢滑到0dp的动画
问题原因
你当前代码的核心冲突在于同时使用了AnimatedVisibility内置的slideOutVertically动画和手动维护的yPosition状态:
LaunchedEffect会在visible状态变化时直接将yPosition赋值为0dp,导致组件瞬间跳到目标位置;- 随后
slideOutVertically默认会把组件滑出父容器范围,最终呈现出"直接跳到0后隐藏"的效果,完全偏离了缓慢过渡的需求。
修正方案一:自定义位置+透明度动画(推荐)
通过animateDpAsState控制顶部内边距的平滑变化,配合animateFloatAsState实现淡出效果,精准控制从50dp逐步移动到0dp的过程:
@OptIn(ExperimentalAnimationApi::class) @Preview(showBackground = true) @Composable fun MoveText() { var isVisible by remember { mutableStateOf(true) } // 控制顶部内边距的动画:显示时50dp,隐藏时0dp,4秒缓慢过渡 val topPadding by animateDpAsState( targetValue = if (isVisible) 50.dp else 0.dp, animationSpec = tween(durationMillis = 4000) ) // 同步控制透明度动画,实现滑到0dp后淡出 val alpha by animateFloatAsState( targetValue = if (isVisible) 1f else 0f, animationSpec = tween(durationMillis = 4000) ) ScrollComposeTheme { Column( modifier = Modifier .fillMaxSize() .padding(start = 16.dp, top = 16.dp) ) { // 动画过程中保持组件可见,直到透明度完全为0 if (isVisible || alpha > 0f) { Column( modifier = Modifier .padding(top = topPadding) .alpha(alpha) ) { Icon( imageVector = Icons.Default.ShoppingCart, tint = if (alpha > 0.5f) Color.Black else Color.Gray, contentDescription = null, ) Text( text = "Hello, Anna", fontSize = 20.sp, color = if (alpha > 0.5f) Color.Black else Color.Gray, ) } } Button( modifier = Modifier.absoluteOffset(y = 10.dp), onClick = { isVisible = !isVisible } ) { Text(text = "Move Text") } } } }
修正方案二:调整AnimatedVisibility退出动画
如果你想保留AnimatedVisibility的使用,可以修改slideOutVertically的目标偏移量,让组件向上移动50dp而非滑出父容器:
@OptIn(ExperimentalAnimationApi::class) @Preview(showBackground = true) @Composable fun MoveText() { var visible by remember { mutableStateOf(true) } val initialTopPadding = 50.dp ScrollComposeTheme { Column( modifier = Modifier .fillMaxSize() .padding(start = 16.dp, top = 16.dp) ) { AnimatedVisibility( visible = visible, modifier = Modifier.padding(top = initialTopPadding), exit = slideOutVertically( animationSpec = tween(4000), // 设置目标偏移:向上移动initialTopPadding的距离,到达top=0的位置 targetOffsetY = { -initialTopPadding.toPx().toInt() } ) + fadeOut(tween(4000)) // 同步添加淡出动画 ) { val color by transition.animateColor(label = "color") { state -> if (state == EnterExitState.Visible) Color.Black else Color.Gray } Column { Icon( imageVector = Icons.Default.ShoppingCart, tint = color, contentDescription = null, ) Text( text = "Hello, Anna", fontSize = 20.sp, color = color, ) } } Button( modifier = Modifier.absoluteOffset(y = 10.dp), onClick = { visible = !visible } ) { Text(text = "Move Text") } } } }
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

