如何为Jetpack Compose的BottomSheetScaffold设置半透明黑色背景
解决Jetpack Compose BottomSheetScaffold半透明遮罩设置问题
问题原因
你现在设置的sheetBackgroundColor = Color.Transparent只会修改底部sheet本身的背景色,而BottomSheetScaffold默认不会自带底层半透明遮罩,所以无法实现你要的类似XML中BottomSheetDialogFragment的背景效果。
解决方案
方案1:在现有BottomSheetScaffold基础上手动添加遮罩层
监听底部sheet的展开状态,在主内容上方叠加半透明遮罩即可,修改后代码如下:
@Composable fun BottomSheet( modifier: Modifier = Modifier, title: String, content: String, buttonText: String, composable: @Composable () -> Unit, isOpen: (Boolean) -> Unit ) { val coroutineScope = rememberCoroutineScope() val bottomSheetScaffoldState = rememberBottomSheetScaffoldState( bottomSheetState = BottomSheetState(BottomSheetValue.Expanded) ) // 判断是否需要显示遮罩 val showScrim = bottomSheetScaffoldState.bottomSheetState.isExpanded BottomSheetScaffold( sheetBackgroundColor = Color.Transparent, scaffoldState = bottomSheetScaffoldState, sheetGesturesEnabled = false, sheetContent = { // 给sheet内容加白色背景,不然内容也会透明 Column( Modifier .fillMaxWidth() .background( color = Color.White, shape = RoundedCornerShape(topEnd = medium, topStart = medium) ) .padding(8.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = title, style = AppFont.PoppinsTypography.button ) Spacer(modifier = modifier.size(8.dp)) Text( text = content, style = AppFont.PoppinsTypography.body1 ) Spacer(modifier = modifier.size(16.dp)) Button(colors = ButtonDefaults.buttonColors( backgroundColor = AppColor.brandColor.BLUE_DE_FRANCE, contentColor = AppColor.neutralColor.DOCTOR ), shape = RoundedCornerShape( small ), onClick = { coroutineScope.launch { bottomSheetScaffoldState.bottomSheetState.collapse() isOpen.invoke(false) } }) { Text( text = buttonText, style = AppFont.PoppinsTypography.button ) } } }, sheetShape = RoundedCornerShape(topEnd = medium, topStart = medium), sheetPeekHeight = 0.dp, drawerGesturesEnabled = false ) { innerPadding -> Box(modifier = Modifier .fillMaxSize() .padding(innerPadding)) { // 原有主内容 composable() // 半透明遮罩层 if (showScrim) { Spacer(modifier = Modifier .fillMaxSize() .background(Color.Black.copy(alpha = 0.5f)) .clickable( // 去掉点击涟漪效果,和系统弹窗行为一致 indication = null, interactionSource = remember { MutableInteractionSource() } ) { coroutineScope.launch { bottomSheetScaffoldState.bottomSheetState.collapse() isOpen(false) } } ) } } } }
方案2:改用官方ModalBottomSheetLayout(更推荐)
该组件是官方专门用来实现模态底部弹窗的,自带遮罩层,不需要手动写遮罩逻辑,效果和BottomSheetDialogFragment完全一致,实现代码如下:
@Composable fun ModalBottomSheet( modifier: Modifier = Modifier, title: String, content: String, buttonText: String, composable: @Composable () -> Unit, isOpen: (Boolean) -> Unit ) { val coroutineScope = rememberCoroutineScope() val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) // 初始自动展开弹窗 LaunchedEffect(key1 = Unit) { sheetState.show() } // 监听弹窗关闭回调 LaunchedEffect(key1 = sheetState.isVisible) { if (!sheetState.isVisible) { isOpen(false) } } ModalBottomSheetLayout( sheetState = sheetState, // 直接设置遮罩层颜色,调整alpha可以控制透明度 scrimColor = Color.Black.copy(alpha = 0.5f), sheetShape = RoundedCornerShape(topStart = medium, topEnd = medium), sheetContent = { Column( Modifier .fillMaxWidth() .padding(8.dp), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text( text = title, style = AppFont.PoppinsTypography.button ) Spacer(modifier = modifier.size(8.dp)) Text( text = content, style = AppFont.PoppinsTypography.body1 ) Spacer(modifier = modifier.size(16.dp)) Button(colors = ButtonDefaults.buttonColors( backgroundColor = AppColor.brandColor.BLUE_DE_FRANCE, contentColor = AppColor.neutralColor.DOCTOR ), shape = RoundedCornerShape(small), onClick = { coroutineScope.launch { sheetState.hide() } }) { Text( text = buttonText, style = AppFont.PoppinsTypography.button ) } } } ) { composable() } }
注意事项
- 如果你使用的是Material3版本的Compose,
ModalBottomSheet的API会有小幅度调整,核心逻辑不变,替换为对应版本的API即可。 - 给sheet设置透明背景后,一定要给内容层加对应背景色,避免内容也变成透明。
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

