Jetpack Compose如何实现Modal Bottom Sheet遮罩色显示在状态栏的效果
问题原因
默认ModalBottomSheetLayout的遮罩绘制范围仅限自身布局占用的区域,默认布局不会延伸到系统状态栏区域,因此遮罩无法覆盖状态栏。
解决步骤
1. 配置Activity窗口参数
首先需要让应用内容可以绘制到状态栏区域,在你的ActivityonCreate方法中添加如下配置:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 设置状态栏透明 window.statusBarColor = android.graphics.Color.TRANSPARENT // 允许内容绘制到系统栏区域 WindowCompat.setDecorFitsSystemWindows(window, false) }
如果你的项目已经开启了Edge-To-Edge显示,这一步可以跳过。
2. 修改Compose布局代码
给最外层的ModalBottomSheetLayout添加Modifier,让它的绘制范围覆盖全屏包括状态栏,内部的Scaffold正常处理系统栏间距即可,修改后的代码如下:
val modalBottomSheetState = rememberModalBottomSheetState( initialValue = ModalBottomSheetValue.Hidden, ) val coroutineScope = rememberCoroutineScope() // 可自定义遮罩颜色,这里用默认值 val scrimColor = ModalBottomSheetDefaults.scrimColor ModalBottomSheetLayout( sheetState = modalBottomSheetState, sheetContent = { // 原有底部弹窗内容 }, scrimColor = scrimColor, // 关键:让布局填充全屏,包含状态栏区域 modifier = Modifier.fillMaxSize() ) { Scaffold( scaffoldState = scaffoldState, topBar = { // 原有TopBar代码,添加statusBarsPadding避免内容和状态栏重叠 TopAppBar( modifier = Modifier.statusBarsPadding(), title = { Text("页面标题") } ) }, floatingActionButton = { FloatingActionButton( onClick = { coroutineScope.launch { if (!modalBottomSheetState.isAnimationRunning) { if (modalBottomSheetState.isVisible) { modalBottomSheetState.hide() } else { modalBottomSheetState.show() } } } }, ) { Icon( imageVector = Icons.Rounded.Add, contentDescription = "Add", ) } }, modifier = Modifier.fillMaxSize(), ) { innerPadding -> // 原有页面内容代码,处理innerPadding即可 Box(Modifier.padding(innerPadding)) { // 页面内容 } } }
备选兼容方案
如果上述方案在你的设备/依赖版本上有适配问题,可以通过监听底部弹窗的状态动态修改状态栏颜色,和遮罩动画同步:
// 记录页面原始状态栏颜色 val originalStatusBarColor = remember { window.statusBarColor } val scrimColor = ModalBottomSheetDefaults.scrimColor // 跟随弹窗展开进度同步修改状态栏颜色 LaunchedEffect(modalBottomSheetState.progress) { val alpha = modalBottomSheetState.progress.fraction val blendedColor = ColorUtils.blendARGB(originalStatusBarColor, scrimColor.toArgb(), alpha) window.statusBarColor = blendedColor } // 弹窗完全隐藏后恢复原始状态栏颜色 LaunchedEffect(modalBottomSheetState.isVisible) { if (!modalBottomSheetState.isVisible) { window.statusBarColor = originalStatusBarColor } }
效果对比
- 原有View体系预期效果:

- 改造前Compose实现效果:

- 改造后效果和View体系效果完全一致。
内容的提问来源于stack exchange,提问作者Abhimanyu
相关产品推荐
相关产品推荐

