Compose 中的質感設計 3

Jetpack Compose 可讓您實作 Material You 和 Material 3 Expressive,這是新一代的 Material Design。M3 Expressive 是 Material Design 3 的擴充功能,包含經過研究驗證的主題、元件、動作、字體排版等更新,旨在協助您打造使用者喜愛、吸引人且符合需求此外,也支援動態色彩等 Material You 個人化功能。M3 Expressive 與 Android 16 視覺風格和系統 UI 相輔相成。

以下我們將以 Reply 範例應用程式為例,示範 Material Design 3 實作。Reply 範例完全以 Material Design 3 為基礎。

使用 Material Design 3 的 Reply 範例應用程式
圖 1. 使用 Material Design 3 的 Reply 範例應用程式

依附元件

如要在 Compose 應用程式中使用 Material 3,請將 Compose Material 3 依附元件新增至 build.gradle 檔案:

implementation "androidx.compose.material3:material3:$material3_version"

新增依附元件後,您就可以開始在應用程式中加入 Material Design 設計系統,包括顏色、字體排版和形狀。

實驗性 API

部分 M3 API 屬於實驗性質。在此情況下,您必須使用 ExperimentalMaterial3Api 註解,在函式或檔案層級選擇加入:

// import androidx.compose.material3.ExperimentalMaterial3Api
@Composable
fun AppComposable() {
    // M3 composables
}

Material Design 主題設定

M3 主題包含下列子系統:色彩配置、字體排版和形狀。自訂這些值時,系統會自動在您用於建構應用程式的 M3 元件中反映變更。

Material Design 的子系統:顏色、字體排版和形狀
圖 2. Material Design 的子系統:顏色、字體排版和形狀

Jetpack Compose 可透過 M3 MaterialTheme 可組合項實作這些概念:

MaterialTheme(
    colorScheme = /* ...
    typography = /* ...
    shapes = /* ...
) {
    // M3 app content
}

如要設定應用程式內容的主題,請定義應用程式專屬的色彩配置、字體排版和形狀。

色彩配置

色彩配置的基礎是五組主要顏色,每種顏色都與 Material 3 元件所用 13 種色調的調色盤相關。舉例來說,以下是 Reply 淺色主題的色彩配置:

Reply 範例應用程式淺色色彩配置
圖 3. Reply 範例應用程式淺色色彩配置

如想進一步瞭解色彩配置和顏色角色,請前往這個網頁。

生成色彩配置

雖然您可以手動建立自訂 ColorScheme,但使用品牌的來源色彩來產生這個類別是較簡單的做法。您可以使用 Material Design 主題設定建構工具執行這項操作,並視需要匯出 Compose 主題設定程式碼。系統會產生下列檔案:

  • Color.kt 包含主題的顏色,以及針對淺色和深色主題顏色定義的所有角色。

val md_theme_light_primary = Color(0xFF476810)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFC7F089)
// ..
// ..

val md_theme_dark_primary = Color(0xFFACD370)
val md_theme_dark_onPrimary = Color(0xFF213600)
val md_theme_dark_primaryContainer = Color(0xFF324F00)
// ..
// ..

  • Theme.kt 含有淺色和深色色彩配置,以及應用程式主題。

private val LightColorScheme = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    // ..
)
private val DarkColorScheme = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    // ..
)

@Composable
fun ReplyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme =
        if (!darkTheme) {
            LightColorScheme
        } else {
            DarkColorScheme
        }
    MaterialTheme(
        colorScheme = colorScheme,
        content = content
    )
}

如要支援淺色和深色主題,請使用 isSystemInDarkTheme()。根據系統設定,定義要使用的色彩配置:淺色或深色。

動態色彩配置

動態色彩是 Material You 的關鍵部分,其中演算法會從使用者的桌布衍生自訂顏色,並套用至其應用程式和系統 UI。這個調色盤是用來做為產生淺色和深色色彩配置的起點。

Reply 範例應用程式:桌布動態主題設定 (左) 和預設應用程式主題設定 (右)
圖 4. Reply 範例應用程式:桌布動態主題設定 (左) 和預設應用程式主題設定 (右)

動態色彩適用於 Android 12 以上版本。如有動態顏色可用,您可以設定動態 ColorScheme。如果沒有,則應改回使用自訂的淺色或深色 ColorScheme。

ColorScheme 提供建構工具函式,可建立動態淺色或深色色彩配置:

// Dynamic color is available on Android 12+
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colors = when {
    dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
    dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
    darkTheme -> DarkColorScheme
    else -> LightColorScheme
}

顏色使用

您可以透過 MaterialTheme.colorScheme 存取應用程式中的 Material Design 主題顏色:

Text(
    text = "Hello theming",
    color = MaterialTheme.colorScheme.primary
)

每個顏色角色都可以用在各種位置,視元件的狀態、顯眼程度和強調效果而定。

  • Primary 是基本顏色,用於主要元件,例如顯眼的按鈕、啟用中狀態,以及浮起表面的色調。
  • 次要主色用於 UI 中較不顯眼的元件,例如篩選器方塊,可擴大色彩表現的機會。
  • 三次色主要顏色用於衍生對比強調色的角色,可用於平衡原色和二次色,或提高對某個元素的關注度。

Reply 範例應用程式設計在 primary-container 上使用 on-primary-container 顏色,強調所選項目。

主要容器和文字欄位,採用 on-primary-container 顏色。
圖 5. 主要容器和文字欄位,採用 on-primary-container 顏色。

Card(
    colors = CardDefaults.cardColors(
        containerColor =
        if (isSelected) MaterialTheme.colorScheme.primaryContainer
        else
            MaterialTheme.colorScheme.surfaceVariant
    )
) {
    Text(
        text = "Dinner club",
        style = MaterialTheme.typography.bodyLarge,
        color =
        if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer
        else MaterialTheme.colorScheme.onSurface,
    )
}

在「回覆」導覽匣中,您可以看到次要和第三容器顏色如何形成對比,進而產生強調和突顯效果。

懸浮動作按鈕的三級容器和三級容器內容組合。
圖 6. 懸浮動作按鈕的三級容器和三級容器內容組合。

字體排版

Material Design 3 定義了字體比例,包括從 Material Design 2 改編的文字樣式。此外,命名和分組功能也經過簡化,包括顯示、大標題、標題、內文和標籤 (皆有大、中和小三種尺寸)。

Material Design 3 的預設字體排版比例
圖 7. Material Design 3 的預設字體排版比例
M3 預設字型大小/行高
displayLarge Roboto 57/64
displayMedium Roboto 45/52
displaySmall Roboto 36/44
headlineLarge Roboto 32/40
headlineMedium Roboto 28/36
headlineSmall Roboto 24/32
titleLarge New- Roboto Medium 22/28
titleMedium Roboto Medium 16/24
titleSmall Roboto Medium 14/20
bodyLarge Roboto 16/24
bodyMedium Roboto 14/20
bodySmall Roboto 12/16
labelLarge Roboto Medium 14/20
labelMedium Roboto Medium 12/16
labelSmall New Roboto Medium, 11/16

定義字體排版

Compose 提供 M3 Typography 類別,配合現有的 TextStyle 和字型相關類別,可建立 Material 3 類型比例型式:Typography 建構函式提供每種樣式的預設值,因此您可以略過任何不想自訂的參數:

val replyTypography = Typography(
    titleLarge = TextStyle(
        fontWeight = FontWeight.SemiBold,
        fontSize = 22.sp,
        lineHeight = 28.sp,
        letterSpacing = 0.sp
    ),
    titleMedium = TextStyle(
        fontWeight = FontWeight.SemiBold,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.15.sp
    ),
    // ..
)
// ..

大型內文、中型內文和中型標籤,適用於不同的字體排版。
圖 8. 大型內文、中型內文和中型標籤,適用於不同的字體排版。

您的產品不一定要使用 Material Design 輸入比例的 15 個預設樣式。在本範例中,我們選擇了五種大小,其餘樣式則省略。

您可以變更 TextStyle 的預設值,以及 fontFamily 和 letterSpacing 等字型相關屬性,藉此自訂字體排版。

bodyLarge = TextStyle(
    fontWeight = FontWeight.Normal,
    fontFamily = FontFamily.SansSerif,
    fontStyle = FontStyle.Italic,
    fontSize = 16.sp,
    lineHeight = 24.sp,
    letterSpacing = 0.15.sp,
    baselineShift = BaselineShift.Subscript
),

定義 Typography 後,請將其傳遞至 M3 MaterialTheme:

MaterialTheme(
    typography = replyTypography,
) {
    // M3 app Content
}

使用文字樣式

您可以使用 MaterialTheme.typography 擷取提供給 M3 MaterialTheme 可組合項的字體排版:

Text(
    text = "Hello M3 theming",
    style = MaterialTheme.typography.titleLarge
)
Text(
    text = "you are learning typography",
    style = MaterialTheme.typography.bodyMedium
)

如要進一步瞭解 Material 指南,請參閱套用字體排版。

形狀

Material 表面可用不同形狀顯示。形狀可用於吸引注意、識別元件、傳達狀態,以及呈現品牌風格。

形狀比例可定義容器邊角的樣式,提供從方形到全圓形的圓角範圍。

定義形狀

Compose 提供含有擴展參數的 M3 Shapes 類別,可支援新的 M3 形狀。M3 形狀比例與字型比例類似,可讓您在 UI 中呈現多種形狀。

形狀分為不同大小:

  • XS
  • 小
  • 中
  • 大
  • XL

根據預設,每個形狀都有預設值,但您可以覆寫這些值:

val replyShapes = Shapes(
    extraSmall = RoundedCornerShape(4.dp),
    small = RoundedCornerShape(8.dp),
    medium = RoundedCornerShape(12.dp),
    large = RoundedCornerShape(16.dp),
    extraLarge = RoundedCornerShape(24.dp)
)

定義 Shapes 後,即可將其傳遞至 M3 MaterialTheme:

MaterialTheme(
    shapes = replyShapes,
) {
    // M3 app Content
}

使用形狀

您可以自訂 MaterialTheme 中所有元件的形狀比例,也可以依元件個別自訂。

使用預設值套用中型和大型形狀:

Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(
    shape = MaterialTheme.shapes.large,
    onClick = {
    }
) {
    /* fab content */
}

Reply 範例應用程式中,卡片的中型形狀和懸浮動作按鈕的大型形狀。
圖 9。Reply 範例應用程式中,卡片的中型形狀和懸浮動作按鈕的大型形狀

Compose 還有另外兩種形狀:RectangleShape 和 CircleShape。矩形沒有框線半徑,圓形則會顯示完整的圓形邊緣:

Card(shape = RectangleShape) { /* card content */ }
Card(shape = CircleShape) { /* card content */ }

以下範例展示了部分套用預設形狀值的元件:

所有 Material 3 元件的預設形狀值。
圖 10。所有 Material 3 元件的預設形狀值。

如要進一步瞭解 Material 指南,請參閱套用形狀。

強調

M3 的強調效果會使用各種顏色變化及其色彩組合。在 M3 中,有兩種方法可以強調 UI:

  • 使用表面、surface-variant 和背景,搭配已擴充 M3 色彩系統的 on-surface 和 on-surface-variants 顏色。舉例來說,表面可與 on-surface-variant 搭配使用,surface-variant 可與 on-surface 搭配使用,藉此提供不同程度的強調效果。
使用中性色彩組合強調重點。
圖 11. 使用中性色組合強調重點。
  • 為文字使用不同的字型粗細。如上所述,您可以為字體比例提供自訂粗細,以達到不同的強調效果。

bodyLarge = TextStyle(
    fontWeight = FontWeight.Bold
),
bodyMedium = TextStyle(
    fontWeight = FontWeight.Normal
)

高度

Material 3 主要使用色調色彩重疊來表示高度。這是區分容器和表面的新方式,除了使用陰影之外,還使用更加顯眼的色調來提高色調高度。

搭配陰影高度的色調高度
圖 12. 搭配陰影高度的色調高度

深色主題中的高度重疊在 Material 3 中也已改為色調色彩重疊。重疊顏色來自主要色彩運算單元。

Material Design 3 的陰影高度與色調高度
圖 13. Material Design 3 中的陰影高度與色調高度

M3 Surface 是大多數 M3 元件的備用可組合函式,同時支援色調及陰影高度:

Surface(
    modifier = Modifier,
    tonalElevation = /*...
    shadowElevation = /*...
) {
    Column(content = content)
}

Material 元件

Material Design 隨附一組豐富的 Material 元件 (例如按鈕、方塊、資訊卡、導覽列),這些元件已遵循 Material Design 主題設定,可協助您打造精美的 Material Design 應用程式。您可以直接使用具有預設屬性的元件。

Button(onClick = { /*..*/ }) {
    Text(text = "My Button")
}

M3 提供多個版本的相同元件,可根據強調和注意程度用於不同角色。

按鈕強調程度,從懸浮動作按鈕、主要按鈕到文字按鈕
圖 14. 按鈕強調程度:從懸浮動作按鈕、主要按鈕到文字按鈕
  • 用於最重要動作的展開懸浮動作按鈕:

ExtendedFloatingActionButton(
    onClick = { /*..*/ },
    modifier = Modifier
) {
    Icon(
        imageVector = Icons.Default.Edit,
        contentDescription = stringResource(id = R.string.edit),
    )
    Text(
        text = stringResource(id = R.string.add_entry),
    )
}

  • 用於高強調動作的填色按鈕:

Button(onClick = { /*..*/ }) {
    Text(text = stringResource(id = R.string.view_entry))
}

  • 低強調動作的文字按鈕:

TextButton(onClick = { /*..*/ }) {
    Text(text = stringResource(id = R.string.replated_articles))
}

您可以進一步瞭解 Material 按鈕和其他元件。Material 3 提供多種元件套件,例如按鈕、應用程式列、導覽元件,專為不同用途和螢幕大小設計。

Material 也提供多個導覽元件,可協助您根據不同的螢幕大小和狀態實作導覽功能。

NavigationBar 適用於精簡型裝置,且目標目的地不超過 5 個:

NavigationBar(modifier = Modifier.fillMaxWidth()) {
    Destinations.entries.forEach { replyDestination ->
        NavigationBarItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { }
        )
    }
}

NavigationRail 適用於中小型平板電腦或橫向模式的手機。這項功能可為使用者提供人體工學設計,並改善這些裝置的使用者體驗。

NavigationRail(
    modifier = Modifier.fillMaxHeight(),
) {
    Destinations.entries.forEach { replyDestination ->
        NavigationRailItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { }
        )
    }
}

Reply 範例:BottomNavigationBar(左) 和 NavigationRail(右)
圖 15。BottomNavigationBar (左) 和 NavigationRail (右) 的回覆範例

使用預設主題回覆,為所有裝置尺寸提供沉浸式使用者體驗。

NavigationDrawer 適用於中大型平板電腦,因為這類裝置有足夠的空間顯示詳細資料。您可以同時使用 PermanentNavigationDrawer 或 ModalNavigationDrawer 以及 NavigationRail。

PermanentNavigationDrawer(modifier = Modifier.fillMaxHeight(), drawerContent = {
    Destinations.entries.forEach { replyDestination ->
        NavigationRailItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { },
            label = { }
        )
    }
}) {
}

固定式導覽匣的回覆展示
圖 16。Reply 應用程式展示固定式導覽匣

導覽選項可提升使用者體驗、人體工學和可觸及性。如要進一步瞭解 Material 導覽元件,請參閱 Compose 自動調整程式碼研究室。

自訂元件主題

M3 鼓勵個人化和彈性。所有元件都已套用預設顏色,但會提供彈性的 API,可視需要自訂顏色。

大多數元件 (例如資訊卡和按鈕) 都會提供預設物件,其中包含可修改的顏色和高度介面,方便您自訂元件:

val customCardColors = CardDefaults.cardColors(
    contentColor = MaterialTheme.colorScheme.primary,
    containerColor = MaterialTheme.colorScheme.primaryContainer,
    disabledContentColor = MaterialTheme.colorScheme.surface,
    disabledContainerColor = MaterialTheme.colorScheme.onSurface,
)
val customCardElevation = CardDefaults.cardElevation(
    defaultElevation = 8.dp,
    pressedElevation = 2.dp,
    focusedElevation = 4.dp
)
Card(
    colors = customCardColors,
    elevation = customCardElevation
) {
    // m3 card content
}

您可以進一步瞭解如何自訂 Material 3。

系統 UI

Material You 的某些面向,來自 Android 12 以上版本中的全新視覺風格和系統 UI。兩個主要部分是分享關係圖和過度捲動的變更。您無須採取額外工作就能導入這些變更。

漣漪

按下時,分享關係圖現在使用細微的火花來照亮途徑。 Compose Material Ripple 在 Android 系統上使用平台 RippleDrawable,因此 Android 12 以上版本的所有 Material 元件都可使用閃光漣漪效果。

M2 和 M3 的漣漪效果
圖 17。M2 與 M3 的漣漪效果

過度捲動

過度捲動現在可以在捲動容器的邊緣使用延展效果。就 Compose Foundation 1.1.0 以上版本而言,無論 API 級別為何,延伸過度捲動設定在捲動容器可組合項中皆預設為開啟,例如 LazyColumn、LazyRow 以及 LazyVerticalGrid。

在容器邊緣使用延展效果過度捲動
圖 18。在容器邊緣使用延展效果過度捲動

無障礙設定

Material 元件內建無障礙標準,旨在為包容性產品設計奠定基礎。瞭解產品的無障礙功能,可提升所有使用者的可用性,包括低視能、失明、聽力障礙、認知障礙、運動障礙或情境障礙 (例如手臂骨折) 的使用者。

色彩無障礙設計

動態色彩的設計符合色彩對比度的無障礙標準。色調調色盤系統是讓任何色彩配置預設為無障礙的關鍵。

Material 的色彩系統提供標準的色調值和測量方法,可用於達到一目瞭然的對比度。

Reply 範例應用程式:原色、二次色和三次色調色盤 (由上至下)
圖 19. Reply 範例應用程式:原色、二次色和三次色調色盤 (由上至下)

所有 Material 元件和動態主題設定,都已使用一組色調調色盤中的上述顏色角色,這些調色盤是為了符合無障礙需求而選取。不過,如果您要自訂元件,請務必使用適當的顏色角色,避免不相符。

在原色上使用 on-primary,在 primary-container 上使用 on-primary-container,並對其他強調色和中性色採取相同做法,為使用者提供清楚易懂的顏色對比。

在主要容器上使用第三容器,會導致按鈕對比度不佳:

// ✅ Button with sufficient contrast ratio
Button(
    onClick = { },
    colors = ButtonDefaults.buttonColors(
        containerColor = MaterialTheme.colorScheme.primary,
        contentColor = MaterialTheme.colorScheme.onPrimary
    )
) {
}

// ❌ Button with poor contrast ratio
Button(
    onClick = { },
    colors = ButtonDefaults.buttonColors(
        containerColor = MaterialTheme.colorScheme.tertiaryContainer,
        contentColor = MaterialTheme.colorScheme.primaryContainer
    )
) {
}

對比度充足 (左) 與對比度不足 (右)
圖 20. 對比度充足 (左) 與對比度不足 (右)

字體排版無障礙功能

M3 字體資源調度會更新靜態字體資源調度和值,提供簡化但動態的大小類別架構,可跨裝置調整。

舉例來說,在 M3 中,Display Small 可根據裝置情境 (例如手機或平板電腦) 指派不同的值。

大螢幕

Material 提供自動調整版面配置和折疊式裝置的指南,讓應用程式更易於使用,並改善使用者手持大型裝置的人體工學。

Material 提供不同類型的導覽,協助您為大型裝置提供更優質的使用者體驗。

您可以進一步瞭解 Android 大螢幕應用程式品質指南,並查看我們的 Reply 範例,瞭解自動調整和無障礙設計。

瞭解詳情

如要進一步瞭解 Compose 中的 Material Design 主題設定,請參閱下列資源:

範例應用程式

文件

API 參考資料和原始碼

影片