Material Design 3 是 Material Design 的下一个演进版本。它包含更新的主题、组件和 Material You 个性化功能,例如动态颜色。它是对 Material Design 2 的更新,与 Android 12 及更高版本上的新视觉风格和系统 UI 相一致。
本指南重点介绍如何从 Compose Material (androidx.compose.material) Jetpack 库 迁移到 Compose Material 3 (androidx.compose.material3) Jetpack 库。
方法
一般来说,您不应该在单个应用程序中长期使用 M2 和 M3。这是因为这两个设计系统及其各自的库在 UX/UI 设计和 Compose 实现方面存在显著差异。
您的应用程序可能使用一个设计系统,例如使用 Figma 创建的设计系统。在这种情况下,我们也强烈建议您或您的设计团队在开始 Compose 迁移之前将其从 M2 迁移到 M3。如果您的应用程序的 UX/UI 设计基于 M2,则将其迁移到 M3 毫无意义。
此外,您的迁移方法应根据应用程序的大小、复杂性和 UX/UI 设计而有所不同。这样做有助于您最大程度地减少对代码库的影响。您应该采取分阶段的方法进行迁移。
何时迁移
您应该尽快开始迁移。但是,重要的是要考虑您的应用程序是否处于可以从 M2 完全迁移到 M3 的现实位置。在开始之前,有一些阻碍场景需要考虑调查。
场景 | 推荐方法 |
---|---|
没有阻碍 | 开始分阶段迁移 |
M2 中的某个组件尚不可用于 M3。请参阅下面 组件和布局 部分。 | 开始分阶段迁移 |
您或您的设计团队尚未将应用程序的设计系统从 M2 迁移到 M3 | 将设计系统从 M2 迁移到 M3,然后开始分阶段迁移 |
即使您受到上述场景的影响,也应该在提交和发布应用程序更新之前采用分阶段的方法进行迁移。在这种情况下,您将并行使用 M2 和 M3,并在迁移到 M3 的同时逐渐淘汰 M2。
分阶段方法
分阶段迁移的一般步骤如下所示
- 将 M3 依赖项添加到 M2 依赖项旁边。
- 将应用程序主题的 M3 版本添加到应用程序主题的 M2 版本旁边。
- 根据应用程序的大小和复杂性,将各个模块、屏幕或可组合项迁移到 M3(有关详细信息,请参阅以下部分)。
- 完全迁移后,删除应用程序主题的 M2 版本。
- 删除 M2 依赖项。
依赖项
M3 具有与 M2 分开的包和版本
M2
implementation "androidx.compose.material:material:$m2-version"
M3
implementation "androidx.compose.material3:material3:$m3-version"
请参阅 Compose Material 3 版本页面 上的最新 M3 版本。
除了主要的 M2 和 M3 库之外,其他 Material 依赖项没有改变。它们使用 M2 和 M3 包和版本的混合,但这不会影响迁移。它们可以与 M3 一起使用。
库 | 包和版本 |
---|---|
Compose Material 图标 | androidx.compose.material:material-icons-*:$m2-version |
Compose Material 涟漪 | androidx.compose.material:material-ripple:$m2-version |
实验性 API
某些 M3 API 被认为是实验性的。在这种情况下,您需要使用 ExperimentalMaterial3Api
注解在函数或文件级别选择加入。
import androidx.compose.material3.ExperimentalMaterial3Api
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppComposable() {
// M3 composables
}
主题
在 M2 和 M3 中,主题可组合项都命名为 MaterialTheme
,但导入包和参数不同。
M2
import androidx.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes
) {
// M2 content
}
M3
import androidx.compose.material3.MaterialTheme
MaterialTheme(
colorScheme = AppColorScheme,
typography = AppTypography,
shapes = AppShapes
) {
// M3 content
}
颜色
M3 中的 颜色系统 与 M2 有很大不同。颜色参数的数量有所增加,它们具有不同的名称,并且它们与 M3 组件的映射方式不同。在 Compose 中,这适用于 M2 Colors
类、M3 ColorScheme
类和相关函数。
M2
import androidx.compose.material.lightColors
import androidx.compose.material.darkColors
val AppLightColors = lightColors(
// M2 light Color parameters
)
val AppDarkColors = darkColors(
// M2 dark Color parameters
)
val AppColors = if (darkTheme) {
AppDarkColors
} else {
AppLightColors
}
M3
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
val AppLightColorScheme = lightColorScheme(
// M3 light Color parameters
)
val AppDarkColorScheme = darkColorScheme(
// M3 dark Color parameters
)
val AppColorScheme = if (darkTheme) {
AppDarkColorScheme
} else {
AppLightColorScheme
}
鉴于 M2 和 M3 颜色系统之间的重大差异,Color
参数没有合理的映射。相反,请使用 Material Theme Builder 工具 生成 M3 颜色方案。在工具中使用 M2 颜色作为核心源颜色,工具会将其扩展为 M3 颜色方案中使用的色调调色板。以下映射建议用作起点。
M2 | Material Theme Builder |
---|---|
primary |
Primary |
primaryVariant |
Secondary |
secondary |
Tertiary |
surface 或 background |
Neutral |
您可以从工具中复制亮色主题和深色主题的颜色十六进制代码值,并使用它们实现 M3 ColorScheme 实例。或者,Material Theme Builder 可以导出 Compose 代码。
isLight
与 M2 Colors
类不同,M3 ColorScheme
类不包含 isLight
参数。一般来说,您应该尝试在主题级别对需要此信息的任何内容进行建模。例如
M2
import androidx.compose.material.lightColors
import androidx.compose.material.darkColors
import androidx.compose.material.MaterialTheme
@Composable
private fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) darkColors(…) else lightColors(…)
MaterialTheme(
colors = colors,
content = content
)
}
@Composable
fun AppComposable() {
AppTheme {
val cardElevation = if (MaterialTheme.colors.isLight) 0.dp else 4.dp
…
}
}
M3
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.MaterialTheme
val LocalCardElevation = staticCompositionLocalOf { Dp.Unspecified }
@Composable
private fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val cardElevation = if (darkTheme) 4.dp else 0.dp
CompositionLocalProvider(LocalCardElevation provides cardElevation) {
val colorScheme = if (darkTheme) darkColorScheme(…) else lightColorScheme(…)
MaterialTheme(
colorScheme = colorScheme,
content = content
)
}
}
@Composable
fun AppComposable() {
AppTheme {
val cardElevation = LocalCardElevation.current
…
}
}
请参阅 Compose 中的自定义设计系统指南,了解更多信息。
动态颜色
M3 中的一项新功能是 动态颜色。M3 ColorScheme
不使用自定义颜色,而是可以在 Android 12 及更高版本上使用设备壁纸颜色,使用以下函数
排版
M3 中的 排版系统 与 M2 不同。排版参数的数量大致相同,但它们具有不同的名称,并且它们与 M3 组件的映射方式不同。在 Compose 中,这适用于 M2 Typography
类和 M3 Typography
类。
M2
import androidx.compose.material.Typography
val AppTypography = Typography(
// M2 TextStyle parameters
)
M3
import androidx.compose.material3.Typography
val AppTypography = Typography(
// M3 TextStyle parameters
)
以下 TextStyle
参数映射建议用作起点。
M2 | M3 |
---|---|
h1 |
displayLarge |
h2 |
displayMedium |
h3 |
displaySmall |
N/A | headlineLarge |
h4 |
headlineMedium |
h5 |
headlineSmall |
h6 |
titleLarge |
subtitle1 |
titleMedium |
subtitle2 |
titleSmall |
body1 |
bodyLarge |
body2 |
bodyMedium |
caption |
bodySmall |
button |
labelLarge |
N/A | labelMedium |
overline |
labelSmall |
形状
M3 中的 形状系统 与 M2 不同。形状参数的数量有所增加,它们的命名方式不同,并且它们与 M3 组件的映射方式不同。在 Compose 中,这适用于 M2 Shapes
类和 M3 Shapes
类。
M2
import androidx.compose.material.Shapes
val AppShapes = Shapes(
// M2 Shape parameters
)
M3
import androidx.compose.material3.Shapes
val AppShapes = Shapes(
// M3 Shape parameters
)
以下 Shape
参数映射建议用作起点。
M2 | M3 |
---|---|
N/A | extraSmall |
small |
small |
medium |
medium |
large |
large |
N/A | extraLarge |
组件和布局
M2 中的大多数组件和布局都可以在 M3 中使用。但是,也有一些缺失的组件,以及 M2 中不存在的新组件。此外,某些 M3 组件比 M2 中的等效组件具有更多变体。一般来说,M3 API 表面尝试尽可能类似于 M2 中最接近的等效项。
鉴于更新的色彩、排版和形状系统,M3 组件倾向于与新的主题值进行不同的映射。建议您查看 Compose Material 3 源代码中的 tokens 目录 作为这些映射的真实来源。
虽然一些组件需要特殊考虑,但以下函数映射建议作为起点。
缺少的 API:
M2 | M3 |
---|---|
androidx.compose.material.swipeable |
目前尚不可用。 |
替换的 API:
M2 | M3 |
---|---|
androidx.compose.material.BackdropScaffold |
没有 M3 等效项,请迁移到 Scaffold 或 BottomSheetScaffold 。 |
androidx.compose.material.BottomDrawer |
没有 M3 等效项,请迁移到 ModalBottomSheet 。 |
重命名的 API:
所有其他 API:
请参阅 Compose Material 3 API 参考概述中的最新 M3 组件和布局 Compose Material 3 API 参考概述,并关注 发布页面 以获取新的和更新的 API。
脚手架、Snackbar 和导航抽屉
M3 中的脚手架与 M2 不同。在 M2 和 M3 中,主要的布局可组合项都命名为 Scaffold
,但导入包和参数不同。
M2
import androidx.compose.material.Scaffold
Scaffold(
// M2 scaffold parameters
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
// M3 scaffold parameters
)
M2 Scaffold
包含一个 backgroundColor
参数,现在在 M3 Scaffold
中被命名为 containerColor
。
M2
import androidx.compose.material.Scaffold
Scaffold(
backgroundColor = …,
content = { … }
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
containerColor = …,
content = { … }
)
M2 ScaffoldState
类在 M3 中不再存在,因为它包含一个 drawerState
参数,该参数不再需要。要使用 M3 Scaffold
显示 Snackbar,请使用 SnackbarHostState
。
M2
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberScaffoldState
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
content = {
…
scope.launch {
scaffoldState.snackbarHostState.showSnackbar(…)
}
}
)
M3
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) },
content = {
…
scope.launch {
snackbarHostState.showSnackbar(…)
}
}
)
M2 Scaffold
中的所有 drawer*
参数都已从 M3 Scaffold
中删除。这些参数包括 drawerShape
和 drawerContent
。要使用 M3 Scaffold
显示抽屉,请使用导航抽屉可组合项,例如 ModalNavigationDrawer
。
M2
import androidx.compose.material.DrawerValue
import
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberDrawerState
import androidx.compose.material.rememberScaffoldState
val scaffoldState = rememberScaffoldState(
drawerState = rememberDrawerState(DrawerValue.Closed)
)
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
drawerContent = { … },
drawerGesturesEnabled = …,
drawerShape = …,
drawerElevation = …,
drawerBackgroundColor = …,
drawerContentColor = …,
drawerScrimColor = …,
content = {
…
scope.launch {
scaffoldState.drawerState.open()
}
}
)
M3
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.rememberDrawerState
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet(
drawerShape = …,
drawerTonalElevation = …,
drawerContainerColor = …,
drawerContentColor = …,
content = { … }
)
},
gesturesEnabled = …,
scrimColor = …,
content = {
Scaffold(
content = {
…
scope.launch {
drawerState.open()
}
}
)
}
)
顶栏
顶栏 在 M3 中与 M2 中不同。在 M2 和 M3 中,主要的顶栏可组合项都命名为 TopAppBar
,但导入包和参数不同。
M2
import androidx.compose.material.TopAppBar
TopAppBar(…)
M3
import androidx.compose.material3.TopAppBar
TopAppBar(…)
如果您以前在 M2 TopAppBar
中将内容居中,请考虑使用 M3 CenterAlignedTopAppBar
。最好了解 MediumTopAppBar
和 LargeTopAppBar
。
M3 顶栏包含一个新的 scrollBehavior
参数,用于通过 TopAppBarScrollBehavior
类提供不同的滚动功能,例如更改海拔。这与通过 Modifer.nestedScroll
滚动内容协同工作。这在 M2 TopAppBar
中可以通过手动更改 elevation
参数来实现。
M2
import androidx.compose.material.AppBarDefaults
import androidx.compose.material.Scaffold
import androidx.compose.material.TopAppBar
val state = rememberLazyListState()
val isAtTop by remember {
derivedStateOf {
state.firstVisibleItemIndex == 0 && state.firstVisibleItemScrollOffset == 0
}
}
Scaffold(
topBar = {
TopAppBar(
elevation = if (isAtTop) {
0.dp
} else {
AppBarDefaults.TopAppBarElevation
},
…
)
},
content = {
LazyColumn(state = state) { … }
}
)
M3
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
scrollBehavior = scrollBehavior,
…
)
},
content = {
LazyColumn { … }
}
)
底部导航 / 导航栏
M2 中的底部导航在 M3 中已重命名为 导航栏。在 M2 中,存在 BottomNavigation
和 BottomNavigationItem
可组合项,而在 M3 中,存在 NavigationBar
和 NavigationBarItem
可组合项。
M2
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
BottomNavigation {
BottomNavigationItem(…)
BottomNavigationItem(…)
BottomNavigationItem(…)
}
M3
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
NavigationBar {
NavigationBarItem(…)
NavigationBarItem(…)
NavigationBarItem(…)
}
按钮、图标按钮和 FAB
按钮、图标按钮和浮动操作按钮 (FAB) 在 M3 中与 M2 中不同。M3 包含所有 M2 按钮可组合项。
M2
import androidx.compose.material.Button
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.IconButton
import androidx.compose.material.IconToggleButton
import androidx.compose.material.OutlinedButton
import androidx.compose.material.TextButton
// M2 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M2 icon buttons
IconButton(…)
IconToggleButton(…)
// M2 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)
M3
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.TextButton
// M3 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M3 icon buttons
IconButton(…)
IconToggleButton(…)
// M3 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)
M3 还包含新的按钮变体。请在 Compose Material 3 API 参考概述 上查看它们。
开关
开关 在 M3 中与 M2 不同。在 M2 和 M3 中,开关可组合项都命名为 Switch
,但导入包不同。
M2
import androidx.compose.material.Switch
Switch(…)
M3
import androidx.compose.material3.Switch
Switch(…)
表面和海拔
M3 中的表面和海拔系统与 M2 不同。M3 中有两种海拔类型。
- 阴影海拔(投射阴影,与 M2 相同)。
- 色调海拔(叠加颜色,M3 新增)。
在 Compose 中,这适用于 M2 Surface
函数和 M3 Surface
函数。
M2
import androidx.compose.material.Surface
Surface(
elevation = …
) { … }
M3
import androidx.compose.material3.Surface
Surface(
shadowElevation = …,
tonalElevation = …
) { … }
您可以使用 M2 中的 elevation
Dp
值在 M3 中用于 shadowElevation
和/或 tonalElevation
,具体取决于 UX/UI 设计偏好。 Surface
是大多数组件背后的支持可组合项,因此组件可组合项也可能会公开您必须以相同方式迁移的海拔参数。
M3 中的色调海拔取代了 M2 暗色主题中的海拔叠加的概念。因此,ElevationOverlay
和 LocalElevationOverlay
在 M3 中不存在,M2 中的 LocalAbsoluteElevation
在 M3 中已更改为 LocalAbsoluteTonalElevation
。
强调和内容 alpha
M3 中的强调与 M2 大不相同。在 M2 中,强调涉及使用具有特定 alpha 值的 on 颜色来区分文本和图标等内容。在 M3 中,现在有几种不同的方法。
- 使用 on 颜色以及来自扩展的 M3 色彩系统的 variant on 颜色。
- 使用不同的字体粗细来设置文本。
因此,ContentAlpha
和 LocalContentAlpha
在 M3 中不存在,需要替换。
以下映射建议作为起点。
M2 | M3 |
---|---|
onSurface 与 ContentAlpha.high |
onSurface 通常情况下,文本使用 FontWeight.Medium - FontWeight.Black 。 |
onSurface 与 ContentAlpha.medium |
一般来说,onSurfaceVariant 使用 FontWeight.Thin - FontWeight.Normal 来设置文本的字体粗细。 |
onSurface 使用 ContentAlpha.disabled 来设置透明度。 |
onSurface.copy(alpha = 0.38f) |
以下是 M2 和 M3 中图标强调的示例。
M2
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Icon(…)
}
M3
import androidx.compose.material3.LocalContentColor
// High emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
Icon(…)
}
以下是 M2 和 M3 中文本强调的示例。
M2
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
Text(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Text(…)
}
M3
import androidx.compose.material3.LocalContentColor
// High emphasis
Text(
…,
fontWeight = FontWeight.Bold
)
// Medium emphasis
Text(
…,
fontWeight = FontWeight.Normal
)
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
Text(
…,
fontWeight = FontWeight.Normal
)
}
背景和容器
M2 中的背景在 M3 中被称为容器。通常,您可以将 M2 中的 background*
参数替换为 M3 中的 container*
,使用相同的数值。例如:
M2
Badge(
backgroundColor = MaterialTheme.colors.primary
) { … }
M3
Badge(
containerColor = MaterialTheme.colorScheme.primary
) { … }
有用链接
要了解更多关于 Compose 中从 M2 迁移到 M3 的信息,请参阅以下其他资源。
文档
示例应用
- Reply M3 示例应用
- Jetchat 示例应用 M2 到 M3 迁移
- Jetnews 示例应用 M2 到 M3 迁移
- 现在在 Android M3 hero 应用中:core-designsystem 模块
视频
API 参考和源代码
推荐给你
- 注意:链接文本在 JavaScript 关闭时显示。
- Compose 中的 Material Design 2
- Compose 中的 Material Design 3
- Compose 中的自定义设计系统