Jetpack Compose布局(二) - Material组件和布局

在上篇《Jetpack Compose技术快速上手》一文中简单介绍了Compose,那么这边我们就来学习下Compose的布局。由于布局这块涉及内容较多,会分开写。
布局主要包括:布局基础知识、Material组件和布局、自定义布局、Compose中使用ConstraintLayout。

image.png

本文重点讲解Material组件和布局
主要涉及:Material中常用组件Material布局。如下图:

本文涉及主要知识点

Material中常用组件

常用组件包括:按钮文字 Text输入框图标 Icon分割线 Divider复选框 CheckBox切换组件 Switch滑块 Slider进度条 ProgressIndicator信息提示组件 SnackBarTab 和TabRow

按钮
按钮包括:Button 、TextButton、IconButton、IconToggleButton、RadioButton、FloatingActionButton、ExtendedFloatingActionButton。
使用示例:

Column {
        Row(Modifier.fillMaxWidth()
                .horizontalScroll(rememberScrollState())
        ) {
            //1 纯文字按钮
            TextButton(onClick = {}) {
                Text("TextButton")
            }
            Spacer(modifier = Modifier.width(5.dp))
            //2 普通按钮
            Button(onClick = { /*TODO*/ }) {
                Text(text = "Button")
            }
            Spacer(modifier = Modifier.width(5.dp))
            // 3 带Icon的按钮
            IconButton(onClick = { /*TODO*/ }, modifier = Modifier.requiredWidth(120.dp)) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Icon(Icons.Filled.Favorite, contentDescription = "Favorite",
                        modifier = Modifier.size(ButtonDefaults.IconSize)
                    )
                    Spacer(Modifier.size(ButtonDefaults.IconSpacing))
                    Text(text = "IconButton")
                }
            }
        }
        Row {
            Spacer(modifier = Modifier.width(5.dp))
            // 4 IconToggleButton
            IconToggleButton(checked = true, onCheckedChange = {},
                modifier = Modifier.requiredWidth(120.dp)
            ) {
                Text(text = "IconToggleButton")
            }
            Spacer(modifier = Modifier.width(5.dp))
            //5 OutlinedButton
            OutlinedButton(onClick = { /*TODO*/ }) {
                Text(text = "OutlinedButton")
            }
            Spacer(modifier = Modifier.width(5.dp))
            // 6 RadioButton
            RadioButton(selected = true, onClick = { /*TODO*/ })
        }

        //扩展悬浮按钮
        ExtendedFloatingActionButton(
            icon = { Icon(imageVector = Icons.Default.Favorite, contentDescription = "") },
            text = { Text("Like") },
            onClick = { },
        )
    }

预览效果:


material各按钮效果

文本 Text
纯文字可组合函数,源码定义如下:

@Composable
fun Text(
    text: String,                             //要显示的文本内容
    modifier: Modifier = Modifier,  //修饰符,
    color: Color = Color.Unspecified, //文字颜色
    fontSize: TextUnit = TextUnit.Unspecified,//文字大小
    fontStyle: FontStyle? = null,//字体样式,如:normal和Italic斜体
    fontWeight: FontWeight? = null,//文字线条粗细,
    fontFamily: FontFamily? = null,//字体
    letterSpacing: TextUnit = TextUnit.Unspecified,//文字间距
    textDecoration: TextDecoration? = null,//文字上的装饰,如:None、Underline、LineThrough,默认为None
    textAlign: TextAlign? = null,//文字在水平方向的布局
    lineHeight: TextUnit = TextUnit.Unspecified,//文本段落的行高
    overflow: TextOverflow = TextOverflow.Clip,//文字溢出后的处理方式,方式:Clip、Ellipsis(省略...)和Visible,默认为Clip,即裁剪
    softWrap: Boolean = true,//文本是否应在软换行符处换行,默认值为true,即在会自动换行
    maxLines: Int = Int.MAX_VALUE,//最大行数
    onTextLayout: (TextLayoutResult) -> Unit = {},//新布局更新时的回调,也可理解为文字内容发生变化后的回调
    style: TextStyle = LocalTextStyle.current
) {
  ......
}

各参数的含义,已增加了注释,使用的的时候根据自己的需求给对应的参数传值就OK了,这里不举例了。

输入框
在Material库中有两种,分别为:TextField和OutlineTextField。这两种输入框参数基本相同。这里就选择TextField详细介绍下其参数,其源码定义:

@Composable
fun TextField(
    value: String,            //输入的文字内容
    onValueChange: (String) -> Unit,//输入框文字内容变化回调函数
    modifier: Modifier = Modifier,  //修饰符
    enabled: Boolean = true,    //是否可用,包括但不限于输入等操作
    readOnly: Boolean = false, //是否只读,控制是否可输入
    textStyle: TextStyle = LocalTextStyle.current,//输入的文字样式
    label: @Composable (() -> Unit)? = null,//输入框的标签,可用理解为输入框的标题
    placeholder: @Composable (() -> Unit)? = null,//无输入内容时,输入框中的提示信息
    leadingIcon: @Composable (() -> Unit)? = null,//输入框起始位置展示一个icon,可选参数
    trailingIcon: @Composable (() -> Unit)? = null,//输入框结束位置展示一个icon,可选参数
    isError: Boolean = false,//标记输入框中内容是否为错误,如果为true,默认情况下,标签、底部指示器和trailingIcon将以错误颜色显示
    visualTransformation: VisualTransformation = VisualTransformation.None,//输入内容的视觉转换,比如:输入密码时用"*"替代
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,//设置输入框可输入类型,支持:Text、Ascii、Number、Phone、Uri、Email、Password、NumberPassword
    keyboardActions: KeyboardActions = KeyboardActions(),//响应键盘操作时的回调
    singleLine: Boolean = false,//是否单行显示
    maxLines: Int = Int.MAX_VALUE,//最大可显示行数
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape =
        MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),//输入框形状
    colors: TextFieldColors = TextFieldDefaults.textFieldColors()//输入框中各种可设置颜色,包括:输入框文字、label、placeholder、background、leadingIconColor、trailingIconColor、indicatorColor、cursorColor(光标)
) {
    ......
}

两种输入框对比:

  • TextField,默认有带灰色背景,无外边框,获取焦点时其label信息显示在输入框内部;
  • OutlineTextField,默认透明背景色,有边框,获取焦点时label信息显示在边框线上;

示例:

Column {
        //--------------------TextField 输入框 未设置onValueChange时,无论输入何内容均显示“你好”,因为输入内容未赋值给value,与Android原生EditText不同
        TextField(
            //输入框中输入的内容
            value = "",
            onValueChange = {},
            //是否单行显示
            singleLine = true,
            // 输入框提示内容
            label = { Text(text = "TextField")},
            //输入框中文字为空时占位内容
            placeholder = { Text(text = "请输入内容")},
            //在输入框左侧显示一个icon
            leadingIcon = {Icon(painter = rememberVectorPainter(image = Icons.Default.Star), contentDescription = "placeholder")},
            //在输入框最右侧显示一个icon
            trailingIcon = {Icon(painter = rememberVectorPainter(image = Icons.Default.Add), contentDescription = "placeholder")},
            //设置输入框输入类型
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
        )
        //--------------------OutlinedTextField 输入框,可输入内容并显示
        val valueState = remember {
            mutableStateOf("")
        }

        OutlinedTextField(
            value = valueState.value,
            onValueChange = {valueState.value = it},
            singleLine = true,
            // 输入框提示内容
            label = { Text(text = "OutlinedTextField")},
            //输入框中文字为空时占位内容
            placeholder = { Text(text = "请输入内容") },
            //在输入框左侧显示一个icon
            leadingIcon = {Icon(painter = rememberVectorPainter(image = Icons.Default.AccountCircle), contentDescription = "placeholder")},
            //在输入框最右侧显示一个icon
            trailingIcon = {Icon(painter = rememberVectorPainter(image = Icons.Default.Add), contentDescription = "placeholder")},
            //设置输入框输入类型
            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
        )
    }

预览效果如下:


两种输入框预览图

图标Icon
类似Image,在Compose库中内置了一些常用的icon,主要在Icons类中。
源码定义:

@Composable
fun Icon(
    painter: Painter,      //设置资源
    contentDescription: String?,//描述此图标所代表内容的文本
    modifier: Modifier = Modifier,//修饰符
    tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current)//着色,可以理解为要显示的颜色
) {
    ......
}

分割线 Divider
分割线,常用于分割页面内容,便于显示,说白了就是画一条线。
源码定义:

@Composable
fun Divider(
    modifier: Modifier = Modifier,  //修饰符
    color: Color = MaterialTheme.colors.onSurface.copy(alpha = DividerAlpha),//线条颜色
    thickness: Dp = 1.dp,//线条粗细
    startIndent: Dp = 0.dp//线条的起始偏移量
) {
    ......
}

复选框 CheckBox和切换组件 Switch
这两个可组合函数参数类似,合并到一起介绍

@Composable
fun Checkbox(
    checked: Boolean,//是否勾选,或是否打开
    onCheckedChange: ((Boolean) -> Unit)?,//状态发生改变时的回调
    modifier: Modifier = Modifier,//修饰符
    enabled: Boolean = true,//是否可以
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: CheckboxColors = CheckboxDefaults.colors()//颜色相关,包括:checkmarkColor、boxColor、borderColor
) {
    ......
}

示例:

Row {
            //--------------------Switch 组件
            val switchState = remember {
                mutableStateOf(false)
            }
            Switch(checked = switchState.value, onCheckedChange = {switchState.value = it})
            //--------------------Checkbox 勾选框
            val checkState = remember {
                mutableStateOf(false)
            }
            Checkbox(checked = checkState.value, onCheckedChange = {checkState.value = it})
        }

效果:


image.png

滑块 Slider
同Android View系统的Slider。
分析源码:

@Composable
fun Slider(
    value: Float,    //值
    onValueChange: (Float) -> Unit,//滑动值发生变化时的回调
    modifier: Modifier = Modifier,//修饰符
    enabled: Boolean = true,//是否可用
    valueRange: ClosedFloatingPointRange = 0f..1f,//可滑动的值的取值范围
    /*@IntRange(from = 0)*/
    steps: Int = 0,//步数,当大于0时,slider会被分为steps+1段,滑动停止时会自动吸附到最近的点上;值为0时,则可连续滑动,不会被分段
    onValueChangeFinished: (() -> Unit)? = null,//值改变结束后的回调
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    colors: SliderColors = SliderDefaults.colors()//颜色相关的
) {
      ......
}

举例:

//--------------------Slider 滑块
        val sliderState = remember {
            mutableStateOf(0f)
        }
        Slider(value = sliderState.value, onValueChange = {sliderState.value = it},steps = 2)
Slider效果图

进度条
进度条可组合函数,同Android View系统的ProgressBar,分为下面三种:

  • ProgressIndicator,基初的进度条;
  • CircularProgressIndicator,圆形形状的进度条;
  • LinearProgressIndicator,线性形状的进度条;

选取CircularProgressIndicator进行参数分析:

@Composable
fun CircularProgressIndicator(
    /*@FloatRange(from = 0.0, to = 1.0)*/
    progress: Float,//当前的进度
    modifier: Modifier = Modifier,//修饰符
    color: Color = MaterialTheme.colors.primary,//颜色
    strokeWidth: Dp = ProgressIndicatorDefaults.StrokeWidth//进度条粗细
) {
    ......
}

看下显示效果:


圆形进度条和线性进度条

Tab 和TabRow
类似Android View系统中的TabLayout效果。通常Tab会和TabRow搭配使用。
TabRow为固定不可滑动的,若多Tab时需要可滑动,则使用ScrollableTabRow
TabRow参数说明:

@Composable
fun TabRow(
    selectedTabIndex: Int,    //选中的索引
    modifier: Modifier = Modifier,//修饰符
    backgroundColor: Color = MaterialTheme.colors.primarySurface,//背景色
    contentColor: Color = contentColorFor(backgroundColor),//内容颜色
    //指示器
    indicator: @Composable (tabPositions: List) -> Unit = @Composable { tabPositions ->
        TabRowDefaults.Indicator(
            Modifier.tabIndicatorOffset(tabPositions[selectedTabIndex])
        )
    },
    //选项卡行和下面显示的内容之间提供了一层分隔
    divider: @Composable () -> Unit = @Composable {
        TabRowDefaults.Divider()
    },
    tabs: @Composable () -> Unit //内容,多个Tab组合函数
) {
      ......
}

示例:

//--------------------选项卡 TabRow
        val state = remember { mutableStateOf(0) }
        val titles = listOf("消息", "通讯录", "附近","我")
        TabRow(selectedTabIndex = state.value,modifier = Modifier.height(50.dp)) {
            titles.forEachIndexed {index,text->
                Tab(selected = state.value == index, onClick = { state.value = index }) {
                    VerticalImageText(text = text)
                }
            }
        }

        Spacer(modifier = Modifier.height(10.dp))
        //--------------------可滑动选项卡 TabRow
        val sTabState = remember { mutableStateOf(0) }
        val sTitles = listOf("消息", "通讯录", "附近","我","交友","教育","购物")
        ScrollableTabRow(selectedTabIndex = sTabState.value,
            modifier = Modifier.height(50.dp),
            edgePadding = 0.dp) {
            sTitles.forEachIndexed {index,text->
                Tab(selected = sTabState.value == index, onClick = { sTabState.value = index }) {
                    VerticalImageText(text = text)
                }
            }
        }
示例效果图

信息提示组件 SnackBar
类似Android View系统中的Toast,但是SnackBar可以操作按钮。通常与SnackbarHost结合使用,通过使用snackbarHostState的showSnackbar方法控制显示内容。值得注意的是showSnackbar为suspend函数,要在协成调用。
举一个在槽位布局中的使用示例

    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        //floatingActionButton位置
        floatingActionButtonPosition = FabPosition.Center,//居中
        //添加一个floatingActionButton
        floatingActionButton = {
            FloatingActionButton(onClick = {
                //点击按钮,显示一个SnackBar
                scope.launch {
                    //注意:在协成中调用
                    scaffoldState.snackbarHostState.showSnackbar("你点击了FloatingActionButton",actionLabel = "Done")
                }
            }) {
                Icon(imageVector = Icons.Default.Add, contentDescription = "")
            }
        },
        //是否与bottomBar区域重叠,true叠加,false 不叠加
        isFloatingActionButtonDocked = true,
    ) {
         ...
    }

Material布局

为了便于开发者开发,Material提供了多种槽位布局,如:ScaffoldModalDrawerBottomSheetScaffoldBackdropScaffold选项卡(上面已讲到)。

Scaffold
槽位布局,源码中参数如下:

@Composable
fun Scaffold(
    modifier: Modifier = Modifier,//修饰符
    scaffoldState: ScaffoldState = rememberScaffoldState(),//scaffold的状态
    topBar: @Composable () -> Unit = {},//topBar内容
    bottomBar: @Composable () -> Unit = {},//bottomBar的内容
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) },//信息提示可组合函数
    floatingActionButton: @Composable () -> Unit = {},//floatingActionButton
    floatingActionButtonPosition: FabPosition = FabPosition.End,//floatingActionButton的位置
    isFloatingActionButtonDocked: Boolean = false,//是否与bottomBar区域重叠,true叠加,false 不叠加
    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//槽位布局的主内容
) {
      ......
}

示例代码:

/**
 * 采用Scaffold槽位
 */
@Composable
fun ScaffoldCompose(){
    val scaffoldState = rememberScaffoldState()
    val scope = rememberCoroutineScope()
    Scaffold(
        scaffoldState = scaffoldState,
        //顶部工具栏
        topBar = { TopBar(onMenuClick = {scope.launch {
                //控制抽屉显示与关闭
                scaffoldState.drawerState.apply {
                    if (isOpen) close() else open()
                }
            }
        })},
        //底部工具栏
        bottomBar = {
            BottomAppBar(
                //当floatActionButton与bottomBar重叠时剪切样式
                cutoutShape = MaterialTheme.shapes.small.copy(CornerSize(50.dp)),
                ) {
                VerticalImageText(rememberVectorPainter(Icons.Rounded.Email),"消息")
                VerticalImageText(rememberVectorPainter(Icons.Rounded.Menu),"动态")
            }
        },
        //floatingActionButton位置
        floatingActionButtonPosition = FabPosition.Center,//居中
        //添加一个floatingActionButton
        floatingActionButton = {
            FloatingActionButton(onClick = {
                //点击按钮,显示一个SnackBar
                scope.launch {
                    scaffoldState.snackbarHostState.showSnackbar("你点击了FloatingActionButton",actionLabel = "Done")
                }
            }) {
                Icon(imageVector = Icons.Default.Add, contentDescription = "")
            }
        },
        //是否与bottomBar区域重叠,true叠加,false 不叠加
        isFloatingActionButtonDocked = true,
        drawerContent = {DrawerContent()}
    ) {
        ShowMaterialComponents()
    }
}

效果图


image.png

值得注意的是BottomAppBar 支持带有 cutoutShape 参数的 FAB 刘海屏,它接受任何 Shape。例如,FloatingActionButton 使用 MaterialTheme.shapes.small,并将 50% 的边角大小作为其 shape 参数的默认值:

bottomBar = {
            BottomAppBar(
                //当floatActionButton与bottomBar重叠时剪切样式
                cutoutShape = MaterialTheme.shapes.small.copy(CornerSize(50.dp)),
                ) {
                  .....
            }
        },
image.png

模态抽屉式导航栏(ModalDrawer)
上面将了Scaffold,但是如果您想实现不含 Scaffold 的模态抽屉式导航栏,可以使用 ModalDrawer可组合项。它接受与 Scaffold 类似的抽屉式导航栏参数,这里就不对每个参数进行说明了,抽屉的显示位置同Scaffold

@Composable
@OptIn(ExperimentalMaterialApi::class)
fun ModalDrawer(
    drawerContent: @Composable ColumnScope.() -> Unit,
    modifier: Modifier = Modifier,
    drawerState: DrawerState = rememberDrawerState(DrawerValue.Closed),
    gesturesEnabled: Boolean = true,
    drawerShape: Shape = MaterialTheme.shapes.large,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerBackgroundColor: Color = MaterialTheme.colors.surface,
    drawerContentColor: Color = contentColorFor(drawerBackgroundColor),
    scrimColor: Color = DrawerDefaults.scrimColor,
    content: @Composable () -> Unit //屏幕内容
) {
    ......
}

另外,若想让抽屉放到底部,则可使用BottomDrawer实现。

val drawerState = rememberBottomDrawerState(BottomDrawerValue.Closed)
BottomDrawer(
    drawerState = drawerState,
    drawerContent = {
        // Drawer content
    }
) {
    // Screen content
}

底部动作条(BottomSheetScaffold)
用于实现标准的底部动作条,BottomSheetScaffold同样接受与"Scaffold类似的参数,例如 topBarfloatingActionButtonsnackbarHost。其中包含额外的参数,这些参数可提供底部动作条的显示方式。
BottomSheetScafold可接受的参数如下:

@Composable
@ExperimentalMaterialApi
fun BottomSheetScaffold(
    sheetContent: @Composable ColumnScope.() -> Unit,//BottomSheetScaffold的内容
    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
) {
    ......
}

如下示例,例子中可以通过点击悬浮按钮/手势展开/收起底部内容:

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun BottomSheetCompose(){
    val scaffoldState = rememberBottomSheetScaffoldState()
    val scope = rememberCoroutineScope()
    BottomSheetScaffold(
        scaffoldState = scaffoldState, 
        sheetContent = { MySheetContent()},
        sheetPeekHeight = 120.dp,
        floatingActionButton = {
            FloatingActionButton(onClick = {
                    //点击折叠和收起
                      scope.launch {
                          scaffoldState.bottomSheetState.apply {
                              if (isCollapsed) expand() else collapse()
                          }
                      }
                },
                //设置悬浮窗背景色
                backgroundColor = Color.White
            ) {
                Image(painter = painterResource(id = R.drawable.ic_baseline_directions_bike_24), contentDescription = "",
                    //过滤颜色
                    colorFilter = ColorFilter.tint(MaterialTheme.colors.primary)
                )
            }
        }
    ) {
        Text(text = "应用主内容")
    }
}
image.png

背景幕(BackdropScaffold)
背景幕,即有两层布局,可以通过手势滑动上次,来展示下层的内容。
BackdropScaffold 接受一些额外的背景幕参数。例如,您可以使用 peekHeight 和 headerHeight 参数来设置后层的可视高度和前层的最小非活动高度。此外,您还可以使用 gesturesEnabled 参数来切换背景幕是否响应拖动。
其源码中详细参数如下:

@Composable
@ExperimentalMaterialApi
fun BackdropScaffold(
    appBar: @Composable () -> Unit,//topBar
    backLayerContent: @Composable () -> Unit,//背景层内容
    frontLayerContent: @Composable () -> Unit,//前层内容
    modifier: Modifier = Modifier,
    scaffoldState: BackdropScaffoldState = rememberBackdropScaffoldState(Concealed),
    gesturesEnabled: Boolean = true,//前层可滑动
    peekHeight: Dp = BackdropScaffoldDefaults.PeekHeight,//背景层可视高度
    headerHeight: Dp = BackdropScaffoldDefaults.HeaderHeight,//前层header的最小非活动高度
    persistentAppBar: Boolean = true,
    stickyFrontLayer: Boolean = true,
    backLayerBackgroundColor: Color = MaterialTheme.colors.primary,//背景层颜色
    backLayerContentColor: Color = contentColorFor(backLayerBackgroundColor),//背景层内容颜色
    frontLayerShape: Shape = BackdropScaffoldDefaults.frontLayerShape,//前景层Shape
    frontLayerElevation: Dp = BackdropScaffoldDefaults.FrontLayerElevation,
    frontLayerBackgroundColor: Color = MaterialTheme.colors.surface,
    frontLayerContentColor: Color = contentColorFor(frontLayerBackgroundColor),
    frontLayerScrimColor: Color = BackdropScaffoldDefaults.frontLayerScrimColor,
    snackbarHost: @Composable (SnackbarHostState) -> Unit = { SnackbarHost(it) }
) {
      ......
}

示例代码就不贴出来了,太多了,贴一张效果图吧。


BackdropScaffold背景幕效果图

好了,到目前关于Material的常用组件和布局已经讲完了,内容有点多,慢慢看吧。
欢迎留言,一起学习,共同进步!

github - 示例源码
gitee - 示例源码

你可能感兴趣的:(Jetpack Compose布局(二) - Material组件和布局)