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") } } } }
关键说明
- 状态驱动动画:通过
bottomSheetState.progress.fraction获取实时滑动进度,将其直接映射到动画目标值,这就是状态控制动画的核心逻辑——让动画跟随状态变化而自动更新,无需手动触发。 - 动画效果优化:使用
spring动画规范替代tween,更贴合Material Design的动效风格,过渡更自然流畅。 - 通用适配性:这套逻辑同样适用于其他场景,比如根据滚动进度控制控件显示、根据开关状态切换元素位置等,只要将滑动进度替换为对应的状态值即可。
内容的提问来源于stack exchange,提问作者Ionnier
相关产品推荐
相关产品推荐

