You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:25:11