Material Design 3 是新一代 Material Design。它包括更新后的主题和组件,以及动态配色等 Material You 个性化功能。它对 Material Design 2 进行了更新,与 Android 12 及更高版本上的全新视觉风格和系统界面相得益彰。
本指南重点介绍如何从 Compose Material (androidx.compose.material) Jetpack 库迁移至 Compose Material 3 (androidx.compose.material3) Jetpack 库。
方法
一般来说,您不应长期在一个应用中同时使用 M2 和 M3。这是因为这两个设计系统和各自的库在用户体验/界面设计和 Compose 实现方面大相径庭。
您的应用可以使用一个设计系统,例如使用 Figma 创建的系统。在这种情况下,我们强烈建议您或您的设计团队在开始 Compose 迁移之前将代码从 M2 迁移至 M3。如果应用的用户体验/界面设计基于 M2,则将其迁移至 M3 将毫无意义。
此外,迁移方法应当因应用的大小、复杂性和用户体验/界面设计而异。这样做有助于最大限度地降低对代码库的影响。您应当采用一种分阶段的迁移方法。
何时迁移
您应当尽快开始迁移。不过,请务必考虑您的应用是否具备从 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 Ripple | androidx.compose.material:material-ripple:$m2-version |
实验性 API
某些 M3 API 被视为实验性 API。在这种情况下,您需要使用 ExperimentalMaterial3Api
注解在函数或文件级别指定 OptIn:
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 主题构建器工具来生成 M3 配色方案。使用 M2 颜色作为该工具中的核心源颜色,该工具会展开为 M3 配色方案使用的色调调色板。建议从以下映射入手:
M2 | Material 主题构建器 |
---|---|
primary |
Primary |
primaryVariant |
次要 |
secondary |
Tertiary |
surface 或 background |
Neutral |
您可以从该工具中复制浅色主题和深色主题的颜色十六进制代码值,并使用这些值来实现 M3 ColorScheme 实例。或者,Material 主题构建器可以导出 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 中的一项新功能。在 Android 12 及更高版本上,M3 ColorScheme
无需使用自定义颜色,即可通过以下函数使用设备壁纸颜色:
排版
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 |
不适用 | headlineLarge |
h4 |
headlineMedium |
h5 |
headlineSmall |
h6 |
titleLarge |
subtitle1 |
titleMedium |
subtitle2 |
titleSmall |
body1 |
bodyLarge |
body2 |
bodyMedium |
caption |
bodySmall |
button |
labelLarge |
不适用 | 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 |
---|---|
不适用 | extraSmall |
small |
small |
medium |
medium |
large |
large |
不适用 | extraLarge |
组件和布局
M2 中的大多数组件和布局在 M3 中均具有可用性。不过,有些功能缺失,也有一些 M2 中不存在的新功能。此外,M3 中的一些组件的变体也比 M2 中的变体更多。一般而言,M3 API surface 会尽可能与 M2 中的最接近的等效项相类似。
在颜色、排版和形状系统更新之后,M3 组件倾向于以不同的方式映射至新的主题值。建议您查看 Compose Material 3 源代码中的令牌目录,将其作为这些映射的可信来源。
尽管某些组件需要特别加以注意,但建议从以下函数映射入手:
缺少的 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 组件和布局,并密切关注版本页面,了解新的 API 和经过更新的 API。
Scaffold、信息提示控件和抽屉式导航栏
M3 采用与 M2 不同的 Scaffold。在 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
显示信息提示控件,请改用 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(…)
}
按钮、图标按钮和悬浮操作按钮
M3 采用了与 M2 不同的按钮、图标按钮和悬浮操作按钮 (FAB)。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(…)
surface 和高度
M3 采用了与 M2 不同的 surface 和高度系统。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 中,您可以为 M3 中的 shadowElevation
和/或 tonalElevation
使用 elevation
Dp
值,具体取决于用户体验/界面设计偏好。
Surface
是大多数组件的备用可组合项,因此组件可组合项也可能会公开高度参数。您必须以同样方式迁移高度参数。
M3 中的色调高度取代了 M2 深色主题中的高度叠加的概念。因此,ElevationOverlay
和 LocalElevationOverlay
并不存在于 M3 中,并且 M2 中的 LocalAbsoluteElevation
已变更为 M3 中的 LocalAbsoluteTonalElevation
。
强调效果和内容 Alpha 值
M3 采用了与 M2 显著不同的强调效果。在 M2 中,强调效果涉及结合使用on 颜色与特定的 Alpha 值来区分文字和图标等内容。现在,M3 提供了一些不同的方法:
- 结合使用主色与扩展 M3 颜色系统中的相应变体主色。
- 为文本使用不同粗细的字体。
因此,M3 中不存在 ContentAlpha
和 LocalContentAlpha
,需要加以替换。
建议从以下映射入手:
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,请参阅下面列出的其他资源。
文档
示例应用
- 回复 M3 示例应用
- Jetchat 示例应用从 M2 迁移至 M3
- Jetnews 示例应用从 M2 迁移至 M3
- Android M3 中的主应用 :core-designsystem 模块
视频
API 参考文档和源代码
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- Compose 中的 Material Design 2
- Compose 中的 Material Design 3
- Compose 中的自定义设计系统