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 中均具有可用性。不过,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 提供了一些不同的方法:
- 结合使用“on”颜色与扩展 M3 颜色系统中的相应“variant on”颜色。
- 为文本使用不同粗细的字体。
因此,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 中的自定义设计系统
