Android 入门教程
Compose 卡片与容器
本教程共 100 篇 · 第 49 篇 · 更新于 2026-07-28 · 约 8 分钟阅读
AndroidAndroid 入门教程Jetpack ComposeCardScaffoldTopAppBarSurface
49. Compose 卡片与容器
本节目标:学会用 Card 做卡片、Surface 做表面容器、Scaffold 搭建页面骨架(顶栏、底栏、FAB),以及用 BottomSheet 做底部弹层。
Card 卡片
Card 是带阴影和圆角的容器,适合做列表项、信息块:
@Composable
fun ArticleCard(title: String, summary: String) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
shape = RoundedCornerShape(12.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(
title,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
)
Spacer(Modifier.height(8.dp))
Text(
summary,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
}
}
}
| 参数 | 作用 |
|---|---|
elevation | 阴影高度(z 轴) |
shape | 圆角形状 |
colors | 背景和内容颜色 |
Note
- Card 本质是一个带阴影和圆角的 Surface。它适合做需要视觉「浮起」效果的内容块。如果你只需要圆角和背景色,不一定非要用 Card,用
Modifier.clip()+background()就行。
Surface 表面
Surface 是更底层的容器,Card 其实是基于 Surface 实现的。Surface 提供背景色、阴影、裁剪、内容颜色:
Surface(
color = MaterialTheme.colorScheme.primaryContainer,
shape = RoundedCornerShape(8.dp),
modifier = Modifier.padding(8.dp)
) {
Text(
"标签",
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
color = MaterialTheme.colorScheme.onPrimaryContainer
)
}
Tip
- Surface 的
color会自动应用到子内容的默认颜色(比如文字色)。设了primaryContainer背景,子文字默认就是onPrimaryContainer色。这是 Surface 比 Box 好的地方。
Scaffold 脚手架
Scaffold 是 Material Design 的页面骨架,帮你组合顶栏、底栏、FAB、抽屉等标准结构:
@Composable
fun MainScreen() {
Scaffold(
topBar = {
TopAppBar(
title = { Text("首页") },
navigationIcon = {
IconButton(onClick = { }) {
Icon(Icons.Default.Menu, contentDescription = "菜单")
}
},
actions = {
IconButton(onClick = { }) {
Icon(Icons.Default.Search, contentDescription = "搜索")
}
}
)
},
bottomBar = {
NavigationBar {
items.forEach { item ->
NavigationBarItem(
selected = selectedItem == item,
onClick = { selectedItem = item },
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) }
)
}
}
},
floatingActionButton = {
FloatingActionButton(onClick = { }) {
Icon(Icons.Default.Add, contentDescription = "新建")
}
}
) { paddingValues ->
// paddingValues 是 Scaffold 算好的内边距,避免内容被顶栏/底栏遮挡
ContentList(modifier = Modifier.padding(paddingValues))
}
}
Scaffold 的参数都是可选的,按需用:
| 参数 | 作用 |
|---|---|
topBar | 顶部应用栏 |
bottomBar | 底部导航栏 |
floatingActionButton | 悬浮按钮 |
snackbarHost | Snackbar 宿主 |
drawerContent | 侧滑抽屉内容 |
Warning
- Scaffold 的
contentlambda 里有paddingValues参数。一定要用这个 padding,它根据顶栏底栏的高度自动计算,不用它内容会被遮挡。
TopAppBar 顶部栏
TopAppBar(
title = { Text("标题") },
navigationIcon = {
IconButton(onClick = { /* 返回 */ }) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "返回")
}
},
actions = {
IconButton(onClick = { }) {
Icon(Icons.Default.Share, contentDescription = "分享")
}
IconButton(onClick = { }) {
Icon(Icons.Default.MoreVert, contentDescription = "更多")
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer
)
)
navigationIcon:左侧导航按钮(返回、菜单)actions:右侧操作按钮(搜索、分享、更多)
Note
CenterAlignedTopAppBar让标题居中,LargeTopAppBar提供可折叠的大标题。根据设计选。
NavigationBar 底部导航
data class NavItem(val label: String, val icon: ImageVector)
@Composable
fun BottomNav() {
val items = listOf(
NavItem("首页", Icons.Default.Home),
NavItem("搜索", Icons.Default.Search),
NavItem("我的", Icons.Default.Person)
)
var current by remember { mutableStateOf(0) }
NavigationBar {
items.forEachIndexed { index, item ->
NavigationBarItem(
selected = current == index,
onClick = { current = index },
icon = { Icon(item.icon, contentDescription = item.label) },
label = { Text(item.label) }
)
}
}
}
ModalBottomSheet 底部弹层
底部弹出的面板,适合做选项菜单、表单:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetExample() {
var showSheet by remember { mutableStateOf(false) }
Button(onClick = { showSheet = true }) {
Text("打开选项")
}
if (showSheet) {
ModalBottomSheet(
onDismissRequest = { showSheet = false }
) {
Column(modifier = Modifier.padding(16.dp)) {
Text("选项一", modifier = Modifier
.fillMaxWidth()
.clickable { showSheet = false }
.padding(12.dp))
Text("选项二", modifier = Modifier
.fillMaxWidth()
.clickable { showSheet = false }
.padding(12.dp))
}
}
}
}
Tip
onDismissRequest在用户下滑关闭或点遮罩时调用,记得在这里隐藏 Sheet。底部弹层比 Dialog 更适合移动端操作,手指够得到。
Snackbar 提示条
Scaffold 自带 Snackbar 支持:
@Composable
fun SnackbarExample() {
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) }
) { padding ->
Button(
onClick = {
scope.launch {
snackbarHostState.showSnackbar("已保存")
}
}
) {
Text("保存")
}
}
}
小结
Card 做信息卡片,Surface 做底层表面容器。Scaffold 是页面骨架,帮你组合顶栏、底栏、FAB、Snackbar,别忘了用 paddingValues。TopAppBar、NavigationBar、BottomSheet 是最常用的三个结构组件。下一节学习主题和样式。