Jetpack Compose BottomSheetScaffold,ModalBottomSheetLayout,BackdropScaffold的用法

5,331 阅读5分钟

这篇文章会对BottomSheetScaffold,ModalBottomSheetLayout以及BackdropScaffold的使用进行讲解。 我们在前面的文章讲过槽位的控件Scaffold,而今天这几个控件也是典型的槽位控件。

一:BottomSheetScaffold

类似我们之前讲过的Scaffold讲解

先来看看代码
@Composable
@ExperimentalMaterialApi
fun BottomSheetScaffold(
    sheetContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    scaffoldState: BottomSheetScaffoldState = rememberBottomSheetScaffoldState(),
    topBar: (@Composable () -> Unit)? = null,
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },
    floatingActionButton: (@Composable () -> Unit)? = null,
    floatingActionButtonPosition: FabPosition = FabPosition.End,
    sheetGesturesEnabled: Boolean = true,
    sheetShape: Shape = MaterialTheme.shapes.large,
    sheetElevation: Dp = BottomSheetScaffoldDefaults.SheetElevation,
    sheetBackgroundColor: Color = MaterialTheme.colors.surface,
    sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
    sheetPeekHeight: Dp = BottomSheetScaffoldDefaults.SheetPeekHeight,
    drawerContent: @Composable (ColumnScope.() -> Unit)? = null,
    drawerGesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    drawerScrimColor: Color = DrawerDefaults.scrimColor,
    backgroundColor: Color = MaterialTheme.colors.background,
    contentColor: Color = contentColorFor(backgroundColor),
    content: @Composable (PaddingValues) -> Unit
){...}
  • sheetContent 底部抽屉的内容
  • modifier 修饰符Modifier讲解
  • scaffoldState BottomSheetScaffoldState的状态,我们来看看具体可以控制哪几个状态
    @ExperimentalMaterialApi
    @Stable
    class BottomSheetScaffoldState(
      val drawerState: DrawerState,
      val bottomSheetState: BottomSheetState,
      val snackbarHostState: SnackbarHostState
    )
    
    • drawerState可以去控制左边抽屉的状态
    • bottomSheetState 可以去控制底部抽屉的状态
    • snackbarHostState 可以控制Snackbar的状态
  • topBar 顶部控件,可用我们之前讲过的TopAppBar TopAppBar讲解
  • snackbarHost 其实是设置了一个Snackbar控件 关于Snackbar以及snackbarHost属性,我们在Snackbar,Scaffold讲解该篇文章讲过
  • floatingActionButton 浮动的button 我们在各种Button讲解讲过
  • floatingActionButtonPosition 设置floatingActionButton的按钮的位置。是在底部居中还是再右下角,有一半会盖在sheetContent上面
  • sheetGesturesEnabled 是否能通过手指滑动去打开和关闭底部的抽屉
  • sheetShape 底部抽屉的形状
  • sheetElevation 底部抽屉的阴影
  • sheetBackgroundColor 底部抽屉的背景颜色
  • sheetContentColor 底部抽屉的内容颜色
  • sheetPeekHeight 是底部抽屉的初始的高度
  • drawerContent 左边抽屉的内容 比如我们前面文章讲过ModalDrawer
  • drawerGesturesEnabled 是否能通过手指拖动的形式去打开和关闭左边的抽屉
  • drawerShape 左边抽屉的形状
  • drawerElevation 左边抽屉的阴影
  • drawerBackgroundColor 左边抽屉的背景颜色
  • drawerContentColor 左边抽屉的内容的颜色
  • drawerScrimColor 左边抽屉打开的时候,右边剩余部分的颜色值
  • backgroundColor BottomSheetScaffold控件的背景颜色
  • contentColor BottomSheetScaffold控件的内容的颜色
  • content BottomSheetScaffold控件包含的内容 举例:
@ExperimentalMaterialApi
@Preview()
@Composable
fun bottomSheetScaffoldTest() {
    val  scaffoldState = rememberBottomSheetScaffoldState()
    val scope = rememberCoroutineScope()
    BottomSheetScaffold(
        sheetContent = {
            Spacer(modifier = Modifier.height(10.dp))
            Text(text = " sheetContent title")
            Text(text = " sheetContent content")
            Text(text = " sheetContent content2")
            Text(text = " sheetContent content3")
            Text(text = " sheetContent content4")
            Text(text = " sheetContent content5")
            Text(text = " sheetContent content6")
            Text(text = " sheetContent content7")
            Text(text = " sheetContent content8")
            Text(text = " sheetContent content9")
            Spacer(modifier = Modifier.height(10.dp))
        },
        modifier = Modifier.fillMaxWidth(),
        scaffoldState = scaffoldState,
        topBar = { topBarView(scaffoldState) },
//        snackbarHost =
        floatingActionButton = {
            FloatingActionButton(
                onClick = {
                    scope.launch {
                        if(scaffoldState.bottomSheetState.isCollapsed){
                            scaffoldState.bottomSheetState.expand()
                        }else{
                            scaffoldState.bottomSheetState.collapse()
                        }
                    }
                }
            ){

            }
        },
        floatingActionButtonPosition = FabPosition.Center,
        sheetGesturesEnabled = true,
        sheetShape = RoundedCornerShape(2.dp),
        sheetElevation = 8.dp,
        sheetBackgroundColor = Color.Red,
        sheetContentColor = Color.White,
        sheetPeekHeight = 50.dp,
        drawerContent = {
            drawView()
        },
        drawerGesturesEnabled = true,
        drawerShape = RoundedCornerShape(4.dp),
        drawerElevation = 16.dp,
        drawerBackgroundColor = Color.White,
        drawerContentColor = Color.Black,
        drawerScrimColor = DrawerDefaults.scrimColor,
        backgroundColor = Color.White,
        contentColor = Color.Black
    ) {
        Spacer(modifier = Modifier.height(10.dp))
        Text(text = "  BottomSheetScaffold  title")
        Text(text = "  BottomSheetScaffold  content")
        Button(onClick = {
            scope.launch {
                scaffoldState.snackbarHostState.showSnackbar("被打开了","隐藏",SnackbarDuration.Short)
            }
        }) {
            Text(text = "打开SnackBar")
        }
    }
}

@Composable
fun drawView(){
    val drawerState = rememberDrawerState(DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    ModalDrawer(
        drawerContent = {
            Text(text = "ModalDrawer Content",modifier = Modifier
                .fillMaxWidth()
                .height(200.dp))
        },
        drawerState = drawerState,
        gesturesEnabled = true,
        drawerShape = MaterialTheme.shapes.large,
        drawerElevation = DrawerDefaults.Elevation,
        drawerBackgroundColor = Color.Red,
        drawerContentColor = Color.White,
        scrimColor = DrawerDefaults.scrimColor
    ) {
        Column() {
            Text(text = "ModalDrawer Title")
            Text(text = "ModalDrawer Content")
            Button(onClick = {
                scope.launch {
                    drawerState.open()
                }
            }) {
                Text(text = "打开")
            }
        }
    }
}

@ExperimentalMaterialApi
@Composable
fun topBarView(scaffoldState:BottomSheetScaffoldState){
    val scope = rememberCoroutineScope()
    TopAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(48.dp),
        backgroundColor = MaterialTheme.colors.primarySurface,
        elevation = 4.dp,
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {
            Icon(
                imageVector = Icons.Filled.Menu,
                contentDescription = "返回按钮",
                tint = Color.White,
                modifier = Modifier
                    .clickable {
                        // 打开drawer
                        scope.launch {
                            scaffoldState.drawerState.open()
                        }
                    }
                    .padding(start = 12.dp, end = 12.dp)
                    .fillMaxHeight()
            )
            Text(text = "页面标题",fontSize = 17.sp,color = Color.White)
        }
    }
}

二:ModalBottomSheetLayout

先来看看ModalBottomSheetLayout的代码

@Composable
@ExperimentalMaterialApi
fun ModalBottomSheetLayout(
    sheetContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    sheetState: ModalBottomSheetState =
        rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
    sheetShape: Shape = MaterialTheme.shapes.large,
    sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
    sheetBackgroundColor: Color = MaterialTheme.colors.surface,
    sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
    scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
    content: @Composable () -> Unit
) {...}
  • sheetContent 底部抽屉的内容
  • modifier 修饰符
  • sheetState 设置状态。显示和隐藏底部抽屉 默认实现是rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)。ModalBottomSheetValue.Hidden是隐藏,ModalBottomSheetValue.Expanded打开,ModalBottomSheetValue.HalfExpanded 打开一半
  • sheetShape 设置底部抽屉形状
  • sheetElevation 设置底部抽屉的阴影
  • sheetBackgroundColor 设置底部抽屉的背景颜色
  • sheetContentColor 设置底部抽屉内容的颜色
  • scrimColor 设置底部抽屉打开的时候,顶部剩余部分的颜色
  • content ModalBottomSheetLayout的内容 举例:
@ExperimentalMaterialApi
@Preview()
@Composable
fun modalBottomSheetLayoutTest(){
    val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden)
    val scope = rememberCoroutineScope()
    ModalBottomSheetLayout(
        sheetContent = {
            Spacer(modifier = Modifier.height(10.dp))
            Text(text = " sheetContent title")
            Text(text = " sheetContent content")
            Text(text = " sheetContent content2")
            Text(text = " sheetContent content3")
            Text(text = " sheetContent content4")
            Text(text = " sheetContent content5")
            Text(text = " sheetContent content6")
            Text(text = " sheetContent content7")
            Text(text = " sheetContent content8")
            Text(text = " sheetContent content9")
            Spacer(modifier = Modifier.height(10.dp))
        },
        modifier = Modifier.fillMaxWidth(),
        sheetState = sheetState,
        sheetShape = RoundedCornerShape(4.dp),
        sheetElevation = 16.dp,
        sheetBackgroundColor = Color.Red,
        sheetContentColor = Color.White,
        scrimColor = ModalBottomSheetDefaults.scrimColor)
    {
        Column {
            Spacer(modifier = Modifier.height(10.dp))
            Text(text = " ModalBottomSheetLayout title")
            Text(text = " ModalBottomSheetLayout content")
            Button(onClick = {
                scope.launch {
                    if(sheetState.isVisible) sheetState.hide() else sheetState.show()
                }
            }) {
                Text(text = " 打开")
            }
            Spacer(modifier = Modifier.height(10.dp))
        }
    }
}

三:BackdropScaffold

先来看看代码

@Composable
@ExperimentalMaterialApi
fun BackdropScaffold(
    appBar: @Composable () -> Unit,
    backLayerContent: @Composable () -> Unit,
    frontLayerContent: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    scaffoldState: BackdropScaffoldState = rememberBackdropScaffoldState(Concealed),
    gesturesEnabled: Boolean = true,
    peekHeight: Dp = BackdropScaffoldDefaults.PeekHeight,
    headerHeight: Dp = BackdropScaffoldDefaults.HeaderHeight,
    persistentAppBar: Boolean = true,
    stickyFrontLayer: Boolean = true,
    backLayerBackgroundColor: Color = MaterialTheme.colors.primary,
    backLayerContentColor: Color = contentColorFor(backLayerBackgroundColor),
    frontLayerShape: Shape = BackdropScaffoldDefaults.frontLayerShape,
    frontLayerElevation: Dp = BackdropScaffoldDefaults.FrontLayerElevation,
    frontLayerBackgroundColor: Color = MaterialTheme.colors.surface,
    frontLayerContentColor: Color = contentColorFor(frontLayerBackgroundColor),
    frontLayerScrimColor: Color = BackdropScaffoldDefaults.frontLayerScrimColor,
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) }
) {...}
  • appBar 顶部的控件,可用我们之前讲过的TopAppBar TopAppBar讲解
  • backLayerContent 显示在后面被遮挡的内容
  • frontLayerContent 显示在前面的内容
  • modifier 修饰符
  • scaffoldState 状态。可以设置snackbar的状态。还可以设置BackdropScaffoldState的状态。有BackdropValue.Concealed. 表示隐藏了后一层,而激活了前一层 跟BackdropValue.Revealed 表示后一层显示,前一层隐藏
  • gesturesEnabled 可否可用通过手指拖动的形式显示和隐藏前后界面
  • peekHeight 前面的界面举例顶部的距离,也可以理解成后面的界面默认露出显示的高度。默认是56dp
  • headerHeight
  • persistentAppBar 当为true的时候,不管显示还是隐藏后面的界面,appBar都一直显示的。如果值为false,则显示后面的界面的时候,appBar会隐藏
  • stickyFrontLayer 当为true的时候,前面的界面之后下拉到后面界面的内容高度位置。为false 的时候,前面的界面可以一直下拉到屏幕底部(试试效果就知道)
  • backLayerBackgroundColor 后面界面的背景颜色
  • backLayerContentColor 后面界面的内容的颜色
  • frontLayerShape 前面界面的形状
  • frontLayerElevation 前面界面的阴影
  • frontLayerBackgroundColor 前面界面的背景颜色
  • frontLayerContentColor 前面界面的内容的颜色
  • frontLayerScrimColor 前面界面下拉时,顶部预留出来的空白的颜色
  • snackbarHost 设置Snackbar的 举例:
@ExperimentalMaterialApi
@Preview()
@Composable
fun backdropScaffoldTest(){
    val scaffoldState = rememberBackdropScaffoldState(BackdropValue.Concealed)
    val scope = rememberCoroutineScope()
    BackdropScaffold(
        appBar = { topBarView(scaffoldState = scaffoldState) },
        backLayerContent = {
            Column() {
                Text(text = "backLayerContent Title")
                Text(text = "backLayerContent Content")
                Text(text = "backLayerContent Content1")
                Text(text = "backLayerContent Content2")
                Text(text = "backLayerContent Content3")
                Text(text = "backLayerContent Content4")
                Text(text = "backLayerContent Content5")
                Text(text = "backLayerContent Content6")
                Text(text = "backLayerContent Content7")
                Text(text = "backLayerContent Content8")
                Text(text = "backLayerContent Content9")
                Text(text = "backLayerContent Content10")
            }
        },
        frontLayerContent = {
            Column() {
                Text(text = "frontLayerContent Title")
                Text(text = "frontLayerContent Content")
                Text(text = "frontLayerContent Content1")
                Text(text = "frontLayerContent Content2")
                Text(text = "frontLayerContent Content3")
                Text(text = "frontLayerContent Content4")
                Text(text = "frontLayerContent Content5")
                Text(text = "frontLayerContent Content6")
                Text(text = "frontLayerContent Content7")
                Text(text = "frontLayerContent Content8")
                Text(text = "frontLayerContent Content9")
                Text(text = "frontLayerContent Content10")
                Button(onClick = {
                    scope.launch {
                    scaffoldState.snackbarHostState.showSnackbar("显示了Snackbar的内容","隐藏",SnackbarDuration.Short)
                }}) {
                    Text(text = "打开Snackbar")
                }
            }
        },
        scaffoldState = scaffoldState,
        gesturesEnabled = true,
        peekHeight = 48.dp,
        persistentAppBar = true,
        stickyFrontLayer = true,
        backLayerBackgroundColor = Color.Red,
        backLayerContentColor = Color.White,
        frontLayerShape = BackdropScaffoldDefaults.frontLayerShape,
        frontLayerElevation = BackdropScaffoldDefaults.FrontLayerElevation,
        frontLayerBackgroundColor = Color.White,
        frontLayerContentColor = Color.Black,
        frontLayerScrimColor = BackdropScaffoldDefaults.frontLayerScrimColor,
    )
}


@ExperimentalMaterialApi
@Composable
fun topBarView(scaffoldState:BackdropScaffoldState){
    val scope = rememberCoroutineScope()
    TopAppBar(
        modifier = Modifier
            .fillMaxWidth()
            .height(48.dp),
        backgroundColor = MaterialTheme.colors.primarySurface,
        elevation = 4.dp,
        contentPadding = AppBarDefaults.ContentPadding
    ) {
        Row(modifier = Modifier.fillMaxWidth(),verticalAlignment = Alignment.CenterVertically) {
            Icon(
                imageVector = Icons.Filled.Menu,
                contentDescription = "返回按钮",
                tint = Color.White,
                modifier = Modifier
                    .clickable {
                        // 打开drawer
                        scope.launch {
                            if (scaffoldState.isConcealed) scaffoldState.reveal() else scaffoldState.conceal()
                        }
                    }
                    .padding(start = 12.dp, end = 12.dp)
                    .fillMaxHeight()
            )
            Text(text = "页面标题",fontSize = 17.sp,color = Color.White)
        }
    }
}