概述
Scaffold 是 Compose 给咱们准备的页面搭积木神器,一个函数就能把主页面的骨架搭得明明白白。别的不说,单看它那参数列表,topBar 、bottomBar 、snackbarHost 、floatingActionButton 基本上一个页面该有的全给你安排上了。
kotlin
Scaffold(
modifier: Modifier = Modifier,
// 顶部区域,一般用于顶部标题栏
topBar: @Composable () -> Unit = {},
// 底部区域,一般用于底部导航栏
bottomBar: @Composable () -> Unit = {},
// SnackBar (默认位置在bottom和floatingButton上方)
snackbarHost: @Composable () -> Unit = {},
// 浮动按钮
floatingActionButton: @Composable () -> Unit = {},
// 浮动按钮的位置
floatingActionButtonPosition: FabPosition = FabPosition.End,
// 容器颜色,相当于background
containerColor: Color = MaterialTheme.colorScheme.background,
// 内容颜色
contentColor: Color = contentColorFor(containerColor),
// 内边距
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
// 内容
content: @Composable (PaddingValues) -> Unit
)
使用 Scaffold 可以很快搭建出一个标准的应用主页面,如下:

topBar
topBar 用于创建顶部标题栏区域。Compose 贴心地提供了 TopAppBar 组件,直接用它就能快速搭建一个标准的标题栏,而且贴心地为你适配了状态栏,当然,如果你想玩点花样,自定义一个炫酷的顶部区域也完全莫得问题。

kotlin
Scaffold(
topBar = {
// Compose 提供的标题栏,也可以编写任意的Compose组件,达到自定义标题栏的目的
TopAppBar(
title = {
Text(text = "Scaffold TopBar")
},
windowInsets = WindowInsets(0, 0, 0, 0),
// 向外扩展的高度,类似于paddingTop 和 paddingBottom
expandedHeight = 50.dp,
// 标题左侧的图标
navigationIcon = {
Icon(
modifier = Modifier
.padding(10.dp),
imageVector = Icons.Rounded.Menu, contentDescription = null
)
},
// 右侧的菜单按钮
actions = {
IconButton(onClick = {}) {
Icon(
imageVector = Icons.Rounded.Add,
contentDescription = null
)
}
}
)
}
// ...
)
bottomBar
主要用来放底部导航栏,带你在不同页面之间切换。
Compose 官方同样给咱们准备了 NavigationBar 组件,直接用就行,不过话说回来,不止能放导航栏,它跟 topBar 一样,接受任意的 Composable 组件------你要是想在这儿放个播放器控件、快捷操作按钮什么的,完全没问题。

kotlin
Scaffold(
bottomBar = {
NavigationBar {
NavigationBarItem(
// 该导航按钮是否被选中
selected = true,
icon = {
Icon(
imageVector = Icons.Filled.Home,
contentDescription = null
)
},
label = {
Text(text = "Home")
},
onClick = {
// 可以通过这个点击事件切换选择的导航按钮
}
)
NavigationBarItem(
selected = false,
icon = {
Icon(
imageVector = Icons.Filled.Class,
contentDescription = null
)
},
label = {
Text(text = "Class")
},
onClick = {
}
)
NavigationBarItem(
selected = false,
icon = {
Icon(
imageVector = Icons.Filled.AccountCircle,
contentDescription = null
)
},
label = {
Text(text = "Profile")
},
onClick = {
}
)
}
}
)
floatingActionButton
FloatingActionButton 是页面上悬浮在角落的小按钮。通过 floatingActionButtonPosition 你可以自由调整它的位置。
| Position | 位置 |
|---|---|
| FabPosition.End | 页面右下方(BottomBar上方) |
| FabPosition.Start | 页面左下方(BottomBar上方) |
| FabPosition.Center | 页面下方居中(BottomBar上方) |
| FabPosition.EndOverlay | 页面右下方(覆盖BottomBar) |
snackbarHost
做 Android 开发的小伙伴对 Toast 和 SnackBar 肯定不陌生吧?Toast 就是那个在界面下方显示一下就消失的提示,而 SnackBar 则是它的升级版------ 不仅能显示提示信息,还能加操作按钮,甚至自定义样式。
Scaffold 的 snackbarHost 参数配合 Compose 提供的 SnackbarHost 组件,就能轻松实现 SnackBar 的全部功能,想什么时候提示就什么时候提示,想怎么提示就怎么提示。
kotlin
// 定义 snackbarHostState,通过操作该对象控制 SnackBar 是否显示
// 在 Compose 中,所有的组件都是函数,而函数不像对象那样可以调用 .show() 这类方法实现显示的效果
// 因此,必须通过给函数传入控制对象来操作页面,这也是Compose的设计哲学,数据驱动页面。
val snackbarHostState = remember { SnackbarHostState() }
// 协程作用域,Compose组件内的协程要和组件的生命周期保持一致,通过这种方式可以获取一个与组件生命周期一致的协程作用域
val scope = rememberCoroutineScope()
Scaffold(
floatingActionButton = {
FloatingActionButton(onClick = {
// 点击按钮后,显示Snackbar
scope.launch {
snackbarHostState.showSnackbar(
// 要显示的信息
"Snackbar",
// 显示的Action按钮,不填写不显示
actionLabel = "Undo",
// 显示时长, Indefinite 表示永久显示直到手动关闭或下一次显示
duration = SnackbarDuration.Short,
// 是否显示关闭按钮
withDismissAction = true
).let { result ->
if (result == SnackbarResult.ActionPerformed) {
// 点击了按钮
} else {
// 没有点击按钮直到消失,或点击了关闭按钮
}
}
}
}) {
Icon(imageVector = Icons.Rounded.Add, contentDescription = null)
}
},
snackbarHost = {
// SnackBar 页面
SnackbarHost(hostState = snackbarHostState) { data ->
Snackbar(
snackbarData = data
)
}
}
)
Content
在 topBar 与 bottomBar 中间部分的内容都是 Content 的内容,Content 组件接收一个 PaddingValues 参数,这个参数是 Scaffold 计算后的除 topBar 和 bottomBar 的padding。如果不使用该PaddingValues(比如设置padding为0), Content 的内容会被topbar遮盖。
kotlin
Scaffold(
// ...
) {
Text(
// 通过设置padding为contentPadding,避免Content内容被 topBar 与 bottomBar 遮盖
modifier = Modifier.padding(contentPadding),
text = "Content 内容"
)
}