Jetpack Compose中Bottom Sheet置于Bottom Bar上方及自定义peekHeight的实现方案
我来帮你搞定这个问题!你现在遇到的Bottom Sheet显示在Bottom Bar下方的问题,本质是布局层级的顺序搞错了,同时我们还能轻松自定义它的peekHeight属性。下面是具体的解决方案:
核心解决思路
- 调整布局层级:把
ModalBottomSheetLayout放到Scaffold的content内部,让Bottom Sheet能覆盖整个Scaffold(包括底部导航栏) - 自定义peekHeight:通过
ModalBottomSheetLayout的sheetPeekHeight参数直接设置初始可见高度 - 适配Bottom Sheet Navigator逻辑:调整导航器中的状态监听,确保和自定义peekHeight兼容
修改后的完整代码
1. 调整AppRouter的布局结构
@ExperimentalMaterialNavigationApi @ExperimentalMaterialApi @Composable fun AppRouter() { val navController = rememberNavController() // 自定义peekHeight,这里设置为120.dp,你可以根据需求调整 val customPeekHeight = 120.dp val bottomSheetNavigator = rememberFullScreenBottomSheetNavigator( skipHalfExpanded = true, customPeekHeight = customPeekHeight ) navController.navigatorProvider += bottomSheetNavigator TriumfTaxiTheme { // Scaffold作为外层,Bottom Bar属于Scaffold的一部分 Scaffold( bottomBar = { BuildBottomBar(navController) }, content = { paddingValues -> // ModalBottomSheetLayout放在Scaffold的content里,让Bottom Sheet覆盖在所有内容之上 ModalBottomSheetLayout( bottomSheetNavigator = bottomSheetNavigator, sheetPeekHeight = customPeekHeight, // 设置自定义的peek高度 sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp) // 可选:给Bottom Sheet加圆角 ) { Box(modifier = Modifier.padding(paddingValues)) { NavHost( navController = navController, startDestination = BottomNavScreenDestinations.BottomNavMap.route ) { composable(route = BottomNavScreenDestinations.BottomNavMap.route) { Home() } // 示例Bottom Sheet路由 bottomSheet(route = "something") { Box( modifier = Modifier .fillMaxWidth() .height(400.dp) .background(Color.White), contentAlignment = Alignment.Center ) { Text(text = "我的Bottom Sheet内容") } } } } } } ) } }
2. 更新rememberFullScreenBottomSheetNavigator逻辑
@ExperimentalMaterialNavigationApi @ExperimentalMaterialApi @Composable fun rememberFullScreenBottomSheetNavigator( animationSpec: AnimationSpec<Float> = SwipeableDefaults.AnimationSpec, skipHalfExpanded: Boolean = true, customPeekHeight: Dp = 0.dp ): BottomSheetNavigator { val screenHeight = LocalConfiguration.current.screenHeightDp.dp val sheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, animationSpec = animationSpec, // 计算半展开比例,匹配自定义的peekHeight halfExpandedRatio = if (skipHalfExpanded) (customPeekHeight / screenHeight).value else 0.5f ) if (skipHalfExpanded) { LaunchedEffect(sheetState) { snapshotFlow { sheetState.isAnimationRunning } .collect { isRunning -> if (!isRunning) { with(sheetState) { // 自动跳过半展开状态,直接切换到展开或隐藏 if (currentValue == ModalBottomSheetValue.HalfExpanded) { animateTo(ModalBottomSheetValue.Expanded) } } } } } } return remember(sheetState) { BottomSheetNavigator(sheetState = sheetState) } }
关键说明
- 布局层级调整:原代码中
ModalBottomSheetLayout包裹Scaffold,导致Bottom Sheet渲染在Scaffold(包括Bottom Bar)下方;调换层级后,Bottom Sheet会覆盖整个Scaffold界面。 - peekHeight自定义:通过
sheetPeekHeight参数直接设置Bottom Sheet的初始可见高度,同时在导航器中计算halfExpandedRatio,确保跳过半展开状态的逻辑和自定义高度兼容。 - 视觉优化:可以给
ModalBottomSheetLayout添加sheetShape属性,让Bottom Sheet顶部呈现圆角,提升界面美观度。
内容的提问来源于stack exchange,提问作者Svilen Rusev
相关产品推荐
相关产品推荐

