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。這是因為兩個設計系統和對應的程式庫,在使用者體驗/使用者介面設計和 Compose 實作方面都有顯著的差異。
您的應用程式可能會使用特定設計系統,例如使用 Figma 建立的系統。在這種情況下,我們也強烈建議您或設計團隊「先」從 M2 遷移至 M3,再開始執行 Compose 遷移作業。如果應用程式以 M2 的使用者體驗/UI 設計為基礎,就無須將應用程式遷移至 M3。
此外,視應用程式的大小、複雜度和使用者體驗/UI 設計而定,遷移方法應有所不同。這樣做能協助您盡量減少對程式碼集的影響。建議您分階段執行遷移作業。
遷移時機
您應該盡快開始進行遷移作業。不過,請務必考量應用程式的實際情況是否適合從 M2 完全遷移至 M3。開始之前,建議您先調查是否存在絆腳石情境:
情境 | 建議做法 |
---|---|
沒有封鎖程式 | 開始階段式遷移作業 |
M3 尚未提供某個 M2 的元件。請參閱下方的「元件和版面配置」一節。 | 開始階段式遷移作業 |
您或設計團隊尚未將應用程式的設計系統從 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 質感設計 3 版本頁面查看 M3 的最新版本。
M2 和 M3 主要程式庫以外的其他 Material 依附元件維持不變。這些依附元件會混合使用 M2 及 M3 套件和版本,但這不會影響遷移作業,也可直接與 M3 搭配使用:
程式庫 | 套件和版本 |
---|---|
Compose 質感設計圖示 | androidx.compose.material:material-icons-*:$m2-version |
Compose 質感設計漣漪效果 | 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
參數沒有合理的對應項目,請改用質感設計主題建構工具產生 M3 色彩配置。使用 M2 色彩做為工具中的「核心」來源色彩,這項工具會將其擴展為 M3 色彩配置所用的色調調色盤。建議您使用下列對應做為起點:
M2 | 質感設計主題建構工具 |
---|---|
primary |
Primary |
primaryVariant |
Secondary (次要) |
secondary |
Tertiary (第三) |
surface 或 background |
普通 |
您可以從工具複製淺色和深色主題的十六進位顏色代碼值,並使用這些值實作 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 的其中一項新功能是動態色彩。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 |
無 | 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 |
元件和版面配置
M3 支援 M2 的大多數元件和版面配置。但是缺少某些項目,還提供一些 M2 中沒有的新項目。此外,部分 M3 元件的變化版本比 M2 的同等元件還多。一般來說,M3 API 介面會盡可能與 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 質感設計 3 API 參考資料總覽,瞭解最新的 M3 元件和版面配置,並隨時留意版本頁面,查看最新和更新的 API 相關資訊。
Scaffold、Snackbar 和導覽匣
M3 的 Scaffold 與 M2 不同。在 M2 和 M3 中,主要版面配置可組合項的名稱都是 Scaffold
,但匯入套件和參數並不相同:
M2
import androidx.compose.material.Scaffold
Scaffold(
// M2 scaffold parameters
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
// M3 scaffold parameters
)
在 M3 Scaffold
中,M2 Scaffold
包含的 backgroundColor
參數現已命名為 containerColor
:
M2
import androidx.compose.material.Scaffold
Scaffold(
backgroundColor = …,
content = { … }
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
containerColor = …,
content = { … }
)
M2 ScaffoldState
類別內含不再需要的 drawerState
參數,因此已不存在於 M3 中。如要使用 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(…)
}
按鈕、圖示按鈕和懸浮動作按鈕
M3 的按鈕、圖示按鈕和懸浮動作按鈕 (FAB) 與 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 = …
) { … }
視使用者體驗/UI 設計偏好而定,您可以在 M3 中為 shadowElevation
和/或 tonalElevation
使用 M2 中的 elevation
Dp
值。Surface
是多數元件的備用可組合項,因此元件可組合項也可能曝露您必須以相同方式遷移的高度參數。
M3 中的色調高度會取代 M2 深色主題中的高度重疊概念。因此,M3 中沒有 ElevationOverlay
和 LocalElevationOverlay
,而 M2 中的 LocalAbsoluteElevation
在 M3 中則已變更為 LocalAbsoluteTonalElevation
。
強調和內容 Alpha 值
M3 中的強調與 M2 有明顯差異。在 M2 中,強調會搭配特定 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,請參閱下列其他資源。
文件
範例應用程式
- Reply M3 範例應用程式
- Jetchat 範例應用程式 M2 至 M3 遷移作業
- Jetnews 範例應用程式 M2 至 M3 遷移作業
- Android M3 主要應用程式 :core-designsystem 模組
影片
API 參考資料和原始碼
為您推薦
- 注意:系統會在 JavaScript 關閉時顯示連結文字
- Compose 中的 Material Design 2
- Compose 中的質感設計 3
- Compose 中的自訂設計系統