Android Material 3 (Material You) 完全指南 —— 从主题到组件一站掌握
Material 3 完全指南
Material 3(Material You)是 Google 最新的设计语言,强调个性化、动态色彩和更灵活的组件系统。本文覆盖 M3 的核心概念、主题系统和全部常用组件的使用方式。
一、快速对比:M2 vs M3
| 维度 | Material 2 | Material 3 |
|---|---|---|
| 色彩 | 固定配色,Primary/Secondary | 动态取色(Dynamic Color),按色相-Tonal Palette 生成 |
| 排版 | 固定 13 个 text style | 更灵活的 Display/Headline/Title/Body/Label 体系 |
| 形状 | 固定 3 级圆角 | 更细粒度的 7 级圆角 |
| 组件后缀 | 大部分以 Material 前缀 | 统一以 Material3 包区分 |
| 暗色模式 | 手动配置 | Surface 自动分层(surfaceColorAtElevation) |
| TopAppBar | TopAppBar() | TopAppBar()(参数更丰富,如 scrollBehavior) |
| Navigation | BottomNavigation | NavigationBar + NavigationBarItem |
二、依赖与入口
1 | // build.gradle.kts (Module) |
MaterialTheme 入口:所有 M3 组件需要在 MaterialTheme 上下文中使用:
1 | MaterialTheme( |
三、颜色系统 —— ColorScheme
3.1 色槽体系(Tonal Palette)
M3 不再使用 Primary/Secondary/Surface 的固定值,而是一组按色相 + 亮度级别生成的色槽:
| 角色 | 用途 |
|---|---|
| primary | 主色,用于 FAB、强调按钮、高亮 |
| onPrimary | 主色上的内容色(通常是白/黑色) |
| primaryContainer | 主色的浅色容器,如选中背景 |
| onPrimaryContainer | 容器上的内容色 |
| secondary | 辅助色 |
| tertiary | 第三色,用于强调对比 |
| background / onBackground | 应用背景 |
| surface / onSurface | 卡片、弹窗等表面色 |
| surfaceVariant / onSurfaceVariant | 表面色的变体(如卡片描边、辅助文字) |
| error / onError / errorContainer / onErrorContainer | 错误色 |
| outline / outlineVariant | 轮廓线颜色 |
| inverseSurface / inverseOnSurface | 反色(Snackbar 常用) |
| scrim | 遮罩层颜色(Dark: black, Light: 未设置) |
3.2 构建 ColorScheme
1 | // 方案一:手动定义亮色方案 |
3.3 Dynamic Color(动态取色)
Android 12 及以上可提取壁纸颜色自动生成配色方案:
1 |
|
3.4 从种子色生成方案
1 |
|
3.5 取色 API 速查
1 | MaterialTheme.colorScheme.primary // 组件中直接取色 |
四、排版系统 —— Typography
M3 的排版从 M2 的 13 级扩展为 15 级,分 5 组:
| 组 | 样式 | M2 对应 | 用途 |
|---|---|---|---|
| Display | displayLarge / displayMedium / displaySmall | h1-h3 | 超大标题 |
| Headline | headlineLarge / headlineMedium / headlineSmall | h4-h6 | 页面大标题 |
| Title | titleLarge / titleMedium / titleSmall | subtitle1 / h6 | 模块标题 |
| Body | bodyLarge / bodyMedium / bodySmall | body1 / body2 / caption | 正文 |
| Label | labelLarge / labelMedium / labelSmall | button / overline / caption | 标签、按钮文字 |
4.1 自定义 Typography
1 | val CustomTypography = Typography( |
五、形状系统 —— Shapes
M3 提供 7 级圆角:
1 | val Shapes = Shapes( |
六、组件总览
6.1 顶层布局 —— Scaffold
1 |
|
6.2 TopAppBar
1 |
|
TopAppBar scrollBehavior 对比:
| Behavior | 行为 |
|---|---|
pinnedScrollBehavior | 标题固定,不收缩 |
enterAlwaysScrollBehavior | 向下滚动时立即重新显示 |
exitUntilCollapsedScrollBehavior | 完全折叠后才重新显示 |
6.3 NavigationBar / NavigationRail
1 | // 底部导航栏(手机) |
NavigationBar 底部间距处理:使用 WindowInsets 适配系统导航栏:
1 | NavigationBar( |
6.4 Buttons
1 | // Filled Button(实心按钮) |
按钮样式速查:
| 类型 | 填充 | 描边 | 阴影 | 推荐场景 |
|---|---|---|---|---|
Button | Primary 色填充 | 无 | 无 | 主要操作 |
FilledTonalButton | SecondaryContainer | 无 | 无 | 次要操作 |
ElevatedButton | Surface | 无 | 有 | 需要抬升的操作 |
OutlinedButton | 透明 | 有 | 无 | 中等强调 |
TextButton | 透明 | 无 | 无 | 低强调(取消、了解详情) |
6.5 FloatingActionButton
1 | // 普通 FAB |
6.6 Card
1 | // Elevated Card |
6.7 Dialog / AlertDialog
1 | var showDialog by remember { mutableStateOf(false) } |
6.8 BottomSheet
1 |
|
6.9 Snackbar
1 | val snackbarHostState = remember { SnackbarHostState() } |
Snackbar 参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
message | String | 提示信息 |
actionLabel | String? | 操作按钮文字 |
duration | SnackbarDuration | Short(4s) / Long(10s) / Indefinite |
withDismissAction | Boolean | 是否显示关闭按钮 |
visuals | SnackbarVisuals | 自定义视觉效果 |
6.10 TextField
1 | var text by remember { mutableStateOf("") } |
TextField 颜色定制:
1 | // 通用 TextField 颜色模板 |
6.11 Switch / Checkbox / RadioButton
1 | var checked by remember { mutableStateOf(true) } |
6.12 Slider / RangeSlider
1 | var sliderValue by remember { mutableFloatStateOf(0.5f) } |
6.13 ProgressIndicator
1 | // 不确定进度(旋转) |
6.14 Chips
1 | // Assist Chip(辅助标签) |
6.15 Badge
1 | // 文字 Badge |
6.16 Tab / TabRow
1 | var tabIndex by remember { mutableIntStateOf(0) } |
TabRow 对比:
| 类型 | 底色 | 可滚动 |
|---|---|---|
PrimaryTabRow | Primary 色 | 否 |
SecondaryTabRow | 透明 / Surface | 否 |
ScrollableTabRow | 自定义 | 是 |
TabRowDefaults.Indicator | 下划线指示器 | — |
TabRowDefaults.SecondaryIndicator | 圆角指示器 | — |
6.17 DatePicker / TimePicker
1 |
|
DatePicker 限制条件:
1 | val state = rememberDatePickerState( |
6.18 DropdownMenu
1 | var expanded by remember { mutableStateOf(false) } |
6.19 分割线 / Divider
1 | // M3 水平分割线(默认包含 start 缩进) |
6.20 ListItem
1 | LazyColumn { |
七、Ripling(涟漪效果)自定义
M3 已经内置涟漪:
1 | MaterialTheme( |
八、PullToRefresh(下拉刷新)
1 |
|
九、SearchBar / DockedSearchBar
1 |
|
十、暗色模式适配
1 |
|
暗色模式注意事项:
| 注意点 | 说明 |
|---|---|
tonalElevation | M3 通过 elevation 自动计算颜色,无需手动写 surfaceVariant |
| 图片适配 | 图标用 tint 或 .colorFilter 反转;大图减少亮度 |
| Scrim | 暗色模式自动使用 Color.Black 作为遮罩 |
| Window 背景 | window.setBackgroundColor(<yourDarkBackground>) |
十一、WindowInsets 系统栏适配
1 | // Edge-to-Edge(全屏内容延伸到系统栏后面) |
十二、ExposedDropdownMenu(下拉选择器)
1 |
|
十三、M2 → M3 迁移速查表
| M2 组件 | M3 替换 |
|---|---|
BottomNavigation | NavigationBar |
BottomNavigationItem | NavigationBarItem |
material 包 | material3 包 |
MaterialTheme.colors.primary | MaterialTheme.colorScheme.primary |
MaterialTheme.colors.surface | MaterialTheme.colorScheme.surface |
MaterialTheme.typography.h1 ~ h6 | displayLarge ~ headlineSmall |
MaterialTheme.typography.subtitle1 | titleLarge |
MaterialTheme.typography.body1 | bodyLarge |
MaterialTheme.typography.body2 | bodyMedium |
MaterialTheme.typography.caption | bodySmall |
MaterialTheme.typography.button | labelLarge |
MaterialTheme.typography.overline | labelSmall |
MaterialTheme.shapes | 参数语义不变,值有调整 |
Divider() | HorizontalDivider() |
Card | ElevatedCard / FilledCard / OutlinedCard |
Snackbar | Snackbar(API 变化,用 SnackbarHost) |
Switch | Switch(M3 样式更新) |
FloatingActionButton | 同上,样式自动适配 M3 |
TextField | OutlinedTextField / FilledTextField(TextField 仅作 M3 填充样式) |
TopAppBar | 相同名称,color 参数改为 TopAppBarDefaults.xxx() |
Slider | 相同名称,colors 参数改为 SliderDefaults.colors() |
BackdropScaffold | 已废弃,M3 无直接替代 |
十四、主题完整封装模板
1 | // Theme.kt |
十五、常见坑与最佳实践
| 问题 | 原因 | 解决 |
|---|---|---|
Divider() 报错 | M3 废弃 Divider | 改用 HorizontalDivider() |
| 颜色不对 | 用了 colors.primary 而非 colorScheme.primary | 全局替换为 MaterialTheme.colorScheme.xxx |
| FAB 被 NavigationBar 遮挡 | 未设置 windowInsets | 给 NavigationBar 加上 windowInsets = NavigationBarDefaults.windowInsets |
| TopAppBar 颜色异常 | 未传 colors 参数 | 使用 TopAppBarDefaults.topAppBarColors() |
| 自定义组件无法拿到主题色 | 不在 MaterialTheme 作用域 | 确保根节点包裹 MaterialTheme { } |
Scaffold 内容重叠 | 未使用 innerPadding | 内容外层包裹 Modifier.padding(innerPadding) |
sliderPosition 状态错乱 | 使用 mutableStateOf 包装 Double | 用 mutableFloatStateOf 避免装箱 |
ModalBottomSheet 拖拽失效 | 放在 Scrollable 内 | 确认 dragHandle 加 BottomSheetDefaults.DragHandle() |
| 暗色模式文字不清 | onSurface 未适配 | 暗色模式下 onSurface 应为浅色 |
全文覆盖 M3 的 ColorScheme(Dynamic Color / Tonal Palette)、Typography、Shapes、以及 25+ 组件的完整用法与代码示例。所有代码均基于 material3:1.3.1 测试通过。