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

Jetpack Compose:基于BottomSheet进度同步Top App Bar的Animated Visibility动画

解决Material 2 BottomSheet与Top App Bar的动画同步问题

核心思路

利用BottomSheet的滑动进度(0=完全收起,1=完全展开)作为动画驱动源,同步控制Top App Bar的垂直位移和透明度:

  • 当BottomSheet完全收起时,Top Bar处于屏幕外底部(偏移自身高度)且完全透明
  • 随着BottomSheet展开,Top Bar逐渐向上移动到顶部位置,同时渐变为完全可见
  • 这种方式能实现你要的“从底部向上”的入场效果,而非单纯修改内容高度导致的压缩问题

代码实现(Compose)

@Composable
fun AnimatedTopBarWithBottomSheet() {
    val bottomSheetState = rememberBottomSheetState(initialValue = BottomSheetValue.Collapsed)
    val scope = rememberCoroutineScope()
    // 获取BottomSheet的滑动进度(0到1的浮点值)
    val slideProgress = bottomSheetState.progress.fraction

    // 动画参数:Top Bar的垂直位移和透明度
    val topBarYOffset by animateFloatAsState(
        targetValue = if (slideProgress >= 1f) 0f else 64f, // 64dp是TopAppBar默认高度
        animationSpec = spring(stiffness = Spring.StiffnessMediumLow)
    )
    val topBarAlpha by animateFloatAsState(
        targetValue = if (slideProgress >= 1f) 1f else 0f,
        animationSpec = spring(stiffness = Spring.StiffnessMediumLow)
    )

    Box(modifier = Modifier.fillMaxSize()) {
        // 主页面内容
        Column(modifier = Modifier.fillMaxSize()) {
            // 这里放置BottomSheet收起时显示的内容
        }

        // 可动画的Top App Bar
        TopAppBar(
            title = { Text("同步显示的标题栏") },
            modifier = Modifier
                .graphicsLayer {
                    translationY = topBarYOffset
                    alpha = topBarAlpha
                }
        )

        // BottomSheet布局
        ModalBottomSheetLayout(
            sheetState = bottomSheetState,
            sheetContent = {
                Column(modifier = Modifier.fillMaxWidth().height(500.dp)) {
                    Text("BottomSheet内容", modifier = Modifier.padding(16.dp))
                    // 添加更多BottomSheet内容
                }
            }
        ) {
            // 触发BottomSheet的按钮
            Button(
                onClick = {
                    scope.launch {
                        bottomSheetState.expand()
                    }
                },
                modifier = Modifier.align(Alignment.Center)
            ) {
                Text("展开BottomSheet")
            }
        }
    }
}

关键说明

  1. 状态驱动动画:通过bottomSheetState.progress.fraction获取实时滑动进度,将其直接映射到动画目标值,这就是状态控制动画的核心逻辑——让动画跟随状态变化而自动更新,无需手动触发。
  2. 动画效果优化:使用spring动画规范替代tween,更贴合Material Design的动效风格,过渡更自然流畅。
  3. 通用适配性:这套逻辑同样适用于其他场景,比如根据滚动进度控制控件显示、根据开关状态切换元素位置等,只要将滑动进度替换为对应的状态值即可。

内容的提问来源于stack exchange,提问作者Ionnier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 03:35:42