Scaffold — 是 Jetpack Compose 中的一个 composable 函数,实现了基于 Material Design 规范的基本屏幕结构。Scaffold 为 TopAppBar、BottomBar、FloatingActionButton、Drawer 和 Snackbar 提供插槽。根据 Google Android Documentation, 2025,Scaffold 是 Compose 应用程序中大多数屏幕的必要元素,因为它管理 Material Design 系统组件的间距。
要点
Scaffold — 是一个 composable 函数,实现了基于 Material Design 规范的屏幕框架。Scaffold 不是常规意义上的容器——它是一个布局管理器,协调多个标准 Material 组件在屏幕上的位置。
Scaffold 管理 TopAppBar、BottomBar 和 FloatingActionButton 的间距,以及系统元素——状态栏和导航面板。这保证内容不会覆盖系统元素,并符合 Material Design 指南。
根据 Material Design Guidelines, 2025,Scaffold 应该是每个应用程序屏幕的根元素。它取代了 View 系统中过时的 CoordinatorLayout,并提供了更简单、更声明式的 API 来构建屏幕布局。
Scaffold 接受 modifier、scaffoldState、topBar、bottomBar、floatingActionButton、drawerContent、snackbarHost 和 content 参数。Content 参数接收 PaddingValues——主要内容必须考虑的间距。
@Composable
fun BasicScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("首页") }
)
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, contentDescription = "Add")
}
}
) { innerPadding ->
Column(
modifier = Modifier.padding(innerPadding)
) {
Text("主要内容")
}
}
}
topBar — 用于放置应用程序顶部面板的插槽,通常是 TopAppBar 或 LargeTopAppBar。Scaffold 自动在 innerPadding 中为内容添加间距,以避免内容覆盖 topBar。TopAppBar 可以包含标题、导航图标和操作。
bottomBar — 用于底部导航面板的插槽。支持 BottomNavigation、BottomAppBar 或 NavigationBar。Scaffold 在计算内容的 innerPadding 时会考虑 bottomBar 的高度。根据 Material Design Guidelines, 2025,bottomBar 应用于具有 3–5 个导航点的屏幕。
floatingActionButton — 用于浮动操作按钮的插槽。Scaffold 根据 Material Design 规范自动定位 FAB——在右下角并具有正确的间距。floatingActionButtonPosition 允许将 FAB 移动到屏幕底部边缘的中央。
在这个示例中,Scaffold 使用了所有主要插槽:带标题的 TopAppBar、带三个导航元素的 BottomBar 和用于主要操作的 FloatingActionButton。
@Composable
fun FullScaffold() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("应用") },
navigationIcon = {
IconButton(onClick = {}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(
icon = { Icon(Icons.Default.Home, "首页") },
label = { Text("Home") },
selected = true,
onClick = {}
)
NavigationBarItem(
icon = { Icon(Icons.Default.Search, "搜索") },
label = { Text("Search") },
selected = false,
onClick = {}
)
}
},
floatingActionButton = {
FloatingActionButton(onClick = {}) {
Icon(Icons.Default.Add, "Add")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("屏幕内容")
}
}
}
ScaffoldState — Scaffold 的状态对象,组合了 DrawerState 和 SnackbarHostState。DrawerState 管理侧边菜单的打开和关闭,而 SnackbarHostState 管理 Snackbar 的显示和隐藏。状态通过 rememberScaffoldState() 创建并传递给 scaffoldState 参数。
DrawerState 提供 open 和 close 方法用于编程控制 Drawer。Drawer 的状态可以是打开、关闭或部分打开。drawerGesturesEnabled 允许禁用通过滑动打开 Drawer 的手势,仅保留通过按钮的编程打开。
SnackbarHostState 管理 Snackbar——屏幕底部的临时通知。showSnackbar 方法显示带有消息和可选操作的 Snackbar。根据 Material Design Guidelines, 2025,Snackbar 应用于短消息,无关键重要信息。
@Composable
fun ScaffoldWithDrawer() {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = {
TopAppBar(
title = { Text("菜单") },
navigationIcon = {
IconButton(onClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}) {
Icon(Icons.Default.Menu, "Menu")
}
}
)
},
drawerContent = {
Column(modifier = Modifier.padding(16.dp)) {
Text("项目 1")
Text("项目 2")
}
}
) { innerPadding ->
Box(modifier = Modifier.padding(innerPadding)) {
Text("内容")
}
}
}
一个完整的屏幕示例使用 Scaffold 包括 TopAppBar、BottomNavigation、FloatingActionButton 和 Snackbar,用于在按下 FAB 时显示通知。ScaffoldState 传递给所有组件以协调状态。
@Composable
fun MainScreen() {
val state = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = state,
topBar = {
TopAppBar(
title = { Text("IT Sectr") },
actions = {
IconButton(onClick = {}) {
Icon(Icons.Default.Notifications, "Notifications")
}
}
)
},
bottomBar = {
NavigationBar {
NavigationBarItem(icon = { Icon(Icons.Default.Home, "首页") },
label = { Text("Home") }, selected = true, onClick = {})
NavigationBarItem(icon = { Icon(Icons.Default.Settings, "设置") },
label = { Text("Settings") }, selected = false, onClick = {})
}
},
floatingActionButton = {
FloatingActionButton(onClick = {
scope.launch {
state.snackbarHostState.showSnackbar("完成")
}
}) {
Icon(Icons.Default.Add, "Add")
}
}
) { padding ->
Box(
modifier = Modifier.padding(padding).fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("欢迎")
}
}
}
innerPadding — 是 Scaffold 传递给 content 块的 PaddingValues。它们包含内容不覆盖 statusBar、navigationBar、topBar 和 bottomBar 所需的间距。使用 innerPadding 是在不同设备上正确显示的必要条件。
Scaffold 根据系统间距和安装的插槽高度自动计算 innerPadding。在具有摄像头岛嵦或屏幕切口的设备上,Scaffold 会调整状态栏的间距。在具有物理按钮的老式设备上,底部间距可能为零。
根据 Android Developers, 2024,innerPadding 应通过 Modifier.padding(innerPadding) 应用于内容的根容器。如果内容使用可滚动容器,则通过 Modifier.consumeWindowInsets 应用 innerPadding,以确保键盘和系统手势的正确操作。
常见问题
Scaffold 不是容器,而是布局管理器,管理 TopAppBar、BottomBar、FAB、Drawer 和 Snackbar 的插槽,并自动处理系统组件的间距。Column 和 Box 仅根据位置元素,不考虑 Material Design。
Scaffold 建议用于使用 Material Design 组件的屏幕。在没有 TopAppBar、BottomBar 或 FAB 的简单屏幕上,Scaffold 不是必须的,但它通过 innerPadding 提供正确的系统间距,这在没有插槽时也很有用。
将 ScaffoldState 传递给 Scaffold 的 scaffoldState 参数,然后在 coroutine 内调用 state.snackbarHostState.showSnackbar(“消息”)。Scaffold 将自动在屏幕底部显示 Snackbar。
可以,如果没有传递 scaffoldState,Scaffold 会默认创建内部状态。但要编程控制 Drawer 和 Snackbar,您需要通过 rememberScaffoldState() 创建并传递 ScaffoldState。
使用 Scaffold 的 floatingActionButtonPosition 参数。默认情况下,FAB 位于右下角 (FabPosition.End)。设置 FabPosition.Center 可将 FAB 放置在屏幕底部边缘的中央。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。