實戰(zhàn) | 在應用中使用 Compose Material 3

Material You 是下一代 Material Design 的發(fā)展方向,也是一種全新的設計愿景: 方便您打造個性化的樣式設計、滿足各種需求并自適應各種屏幕;Jetpack Compose 是用于構建原生 Android 界面的新款現(xiàn)代工具包,可以幫助您更快地構建更出色的應用。

您可能對現(xiàn)有的 Compose Material 庫十分了解,它基于 Material Design 2 規(guī)范,其中包括了 Material 主題、Material 組件和深色主題等功能。新的 Compose Material 3 Jetpack 庫 現(xiàn)已發(fā)布 Alpha 版,它基于 Material Design 3 規(guī)范,包括了更新后的主題、組件以及動態(tài)配色這類 Material You 個性化功能,旨在與新的 Android 12 視覺樣式和系統(tǒng)界面相得益彰。接下來,我們將使用 Jetchat 來說明如何應用 Material Design 3 和 Material You。

如果您更喜歡通過視頻了解此內(nèi)容,請 點擊此處 查看。

Jetchat 是一款使用 Jetpack Compose 構建的示例聊天應用,目前使用 Material Design 2 中的主題和組件。我們將在 Jetchat 中,應用由我們的設計人員提供的 Compose Material 3 庫的更新,其中包括更廣泛的色調(diào)顏色、對組件的最新更新,甚至包括動態(tài)配色以使應用更加個性化,從而使其更加美觀。

△ Jetchat 應用

在開始前,我們首先要將 Material 3 的依賴項添加到模塊的 build.gradle 文件中:

implementation 'androidx.compose.material3:material3:1.0.0-alpha01'

MaterialTheme

我們先來看看 MaterialTheme。現(xiàn)有的 MaterialTheme 可組合項是 Material Design 2 的實現(xiàn),它通過調(diào)整顏色、排版和形狀系統(tǒng),可以在整個應用內(nèi)實現(xiàn)對 Material 2 組件進行主題設置。我們?yōu)?Material Design 3 引入了新版本的 MaterialTheme,可以通過調(diào)整配色方案和排版系統(tǒng)對 Material 3 組件的主題進行設置,而更新 Shape 的功能也會在不久之后加入。

import androidx.compose.material3.MaterialTheme
 
@Composable
fun MaterialTheme (
    colorScheme: ColorScheme,
    typography: Typography,
    // 更新 Shape 的功能即將到來
    content: @Composable () -> Unit
)

首先,我們看一下配色方案。Material Design 3 將顏色細分到特定名稱的顏色槽中。比如 Material 3 組件使用的 Primary、Background 和 Error,這些顏色槽共同形成一種配色方案。部分顏色槽來自 Material Design 2,同時也引入了一些新的顏色槽以擴充整體調(diào)色板。這些顏色槽都包含了美觀的全新默認基準顏色,在淺色和深色主題上都可以應用。

△ 綠色框為 Material You 中新加入的顏色槽

上面這些顏色取自一組色調(diào)調(diào)色板,例如,我們來看一下 Primary 顏色槽。該顏色槽使用的顏色值來自 Primary 色調(diào)調(diào)色板中的不同色調(diào),并根據(jù)淺色和深色主題選擇相應的色調(diào),以滿足無障礙功能要求。

△ Primary 顏色槽

Compose 使用新的 ColorScheme 類對此進行建模,其參數(shù)以 Material Design 3 配色方案中的顏色槽命名。您可以使用 lightColorScheme 函數(shù)創(chuàng)建具有淺色基準值的 ColorScheme 實例;也可以使用自定義顏色覆蓋默認值,或者使用 darkColorScheme 設置深色默認基準值;您還可以使用 isSystemInDarkTheme 工具函數(shù),根據(jù)系統(tǒng)設置在淺色和深色配色方案之間切換。

val AppLightColorScheme = lightColorScheme (
    primary = Color(...),
    // secondary、tertiary 等等
    // 具有淺色基準值的 ColorScheme 實例
)
 
val AppDarkColorScheme = darkColorScheme(
    // primary、secondary、tertiary 等等
    // 具有深色基準值的 ColorScheme 實例
)
 
val dark = isSystemInDarkTheme()
val colorScheme = if (dark) AppDarkColorScheme else AppLightColorScheme
 
// 將 colorScheme 作為參數(shù)傳遞給 MaterialTheme。
MaterialTheme (
    colorScheme = colorScheme,
    // 字型
) {
    // 應用內(nèi)容
}

接下來,我們來看看 Jetchat 的配色方案。Jetchat 的配色方案由 MaterialTheme Builder 工具生成,我們使用 Jetchat 品牌顏色中的藍色和黃色作為 Primary 顏色、Secondary 顏色和 Tertiary 顏色的來源,生成了非常適合 Jetchat 的 Material 3 配色方案,其中涵蓋了用于淺色和深色主題的顏色。Jetchat 所使用的品牌顏色取自 MaterialTheme Builder 工具生成的一組自定義色調(diào)調(diào)色板,下圖中顯示了 Primary 顏色,即藍色的色調(diào)調(diào)色板,以及配色方案中匹配的 Primary 顏色槽。

△ MaterialTheme Builder 工具中生成的 Jetchat 配色方案

要實現(xiàn) Jetchat 配色方案,首先使用 Color 類聲明這些顏色。MaterialTheme Builder 工具還可以為您導出生成的代碼。接下來,便可以使用相應的顏色值聲明 Jetchat 淺色和深色配色方案。

// 來自名為'Blue'的色調(diào)調(diào)色盤的 Primary 顏色
val Blue10 = Color (0xFF000965)
val Blue20 = Color (0xFF00159E)
val Blue30 = Color (0xFF0023DA)
val Blue40 = Color (0xFF1E40FF)
val Blue80 = Color (0xFFBBC3FF)
val Blue90 = Color (0xFFDDE0FF)
 
val JetchatLightColorScheme = lightColorScheme (
    primary = Blue40,
    onPrimary = Color.White,
    primaryContainer = Blue90,
    onPrimaryContainer = Blue10,
    // secondary、tertiary、surface 等等
)
 
val JetchatDarkColorScheme = darkColorScheme (
    primary = Blue80,
    onPrimary = Blue20,
    primaryContainer = Blue30,
    onPrimaryContainer = Blue90,
    // secondary、tertiary、surface 等等
)

我們?yōu)?Jetchat 主題創(chuàng)建了一個新的可組合函數(shù),該函數(shù)接收一個用于判斷深色主題的參數(shù)和一個應用內(nèi)容參數(shù),從而使我們可以在 Jetchat 的淺色和深色配色方案之間切換。接下來,我們將 colorScheme 值和 content 傳遞給內(nèi)部的 MaterialTheme 可組合項,這使我們能夠封裝 Jetchat 內(nèi)容并為應用提供主題。

@Composable
fun JetchatTheme (
    dark: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme = if (dark) JetchatDarkColorScheme else JetchatLightColorScheme
    MaterialTheme (
        colorScheme = colorScheme,
        content = content,
    )
}

下面讓我們看一下 Jetchat 對話界面,界面中的不同部分使用了配色方案中的不同顏色槽。例如,根據(jù)用戶不同,消息頭像的邊框顏色使用 Primary 顏色或 Tertiary 顏色。這里使用 MaterialTheme.colorScheme 訪問主題顏色值。

△ Jetchat 對話界面
@Composable
fun Message(...) {
    val avatarBorderColor = if (isUserMe) {
        MaterialTheme.colorScheme.primary
    } else {
        MaterialTheme.colorScheme.tertiary
    }
    ...
}

動態(tài)配色

接下來,讓我們來了解什么是動態(tài)配色。動態(tài)配色是 Material You 的重要部分,即用算法從用戶的壁紙中提取自定義顏色并應用于應用和系統(tǒng)界面,您可將此作為起點來生成完整的淺色和深色配色方案。

△ Jetchat 的配色方案隨用戶設置的壁紙變化

動態(tài)配色可在 Android 12 及更高版本中使用,要在 Compose 中實現(xiàn)動態(tài) ColorScheme,需要首先檢查 Build.VERSION.SDK。如果動態(tài)配色可用,我們便可以設置動態(tài) ColorScheme;如果不可用,則可以回退到像以前一樣使用 lightColorScheme 或 darkColorScheme:

val dynamic = Build.VERSION.SOK_INT >= Build.VERSION_CODES.S
val colorScheme = if (dynamic) {
    val context = LocalContext.current
    // 使用 dynamicLightColorScheme 函數(shù)創(chuàng)建具有淺色動態(tài)值的 ColorScheme 實例
    // 或使用 dynamicDarkColorScheme 創(chuàng)建具有深色動態(tài)值的實例
    // 傳入 Context 以便從 Android 系統(tǒng)獲取動態(tài)配色資源
    if (dark) dynamiclightColorScheme(context) else dynamicDarkColorScheme(context)
} else {
    // 使用 lightColorScheme 或者 darkColorScheme
}

目前,Jetchat 一直在使用品牌的藍色配色方案,但我們希望增加對基于壁紙的動態(tài)配色方案的支持,以配合用戶的個性化調(diào)整。在本例中,色調(diào)調(diào)色板基于壁紙中的顏色生成,而動態(tài)配色方案則派生自這些色調(diào)調(diào)色板,其中包括用于淺色和深色主題的顏色。

為了在 Jetchat 中實現(xiàn)這一點,我們首先更新 JetchatTheme 為動態(tài)配色添加一個新參數(shù),然后使用該動態(tài)配色參數(shù)設置動態(tài) ColorScheme,或者在不可用時回退到品牌的藍色配色方案。與前面一樣將 colorScheme 值和 content 傳遞給內(nèi)部的 MaterialTheme 可組合項。

@Composable
fun JetchatTheme (
    dark: Boolean = isSystemInDarkTheme (),
    dynamic: Boolean = Build. VERSION.SDK_INT >= Build.VERSION_CODES.S,
    content: @Composable () -> Unit
) {
    // ColorScheme 配置以及 MaterialTheme
    val colorScheme = if (dynamic) {
        val context = LocalContext.current
        if (dark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
    } else {
        if (dark) JetchatDarkColor Scheme else Jetchat Light Color Scheme
    }
 
    MaterialTheme(
        colorScheme = colorScheme, 
        content = content,
    )
}

現(xiàn)在,在 Android 12 及更高版本上,Jetchat 界面可根據(jù)用戶壁紙自動調(diào)整配色,無論是淺色主題還是深色主題都可提供適合品牌的美觀體驗。

△ 自動適配深淺色主題的動態(tài)配色

排版

現(xiàn)在我們已經(jīng)了解了配色方案,接下來讓我們來看看排版。Material Design 3 有了新的字體規(guī)格,包括了由 Material Design 2 適配而來的文本樣式。樣式的命名和分組簡化為顯示、大標題、標題、正文和標簽;每個分組都有大號、中號和小號字體。

△ Material 3 與 Material 2 的字體樣式分組

Compose 使用新的 Typography 類對字體規(guī)格進行建模,其參數(shù)以 Material Design 3 字體規(guī)格中的樣式命名。我們可以使用 Roboto 基準值創(chuàng)建一個 Typography 實例,用自定義文本樣式覆蓋默認值,最后將 Typography 作為參數(shù)傳遞給 MaterialTheme。

import androidx.compose.material3.Typography
 
class Typography (
    val displayLarge: TextStyle,
    val displayMedium: TextStyle,
    val displaySmall: TextStyle,
    // headlineLarge、titleMedium、bodySmall 等等
)
 
val AppTypography = Typography (
    bodyLarge = TextStyle(...),
    // displayLarge、titleMedium、labelSmall 等等
    // 使用默認的 Roboto 基準值
)
 
MaterialTheme (
    typography = AppTypography,
    // colorScheme
) {
    //App content
}

我們再來看看 Jetchat 的排版。設計人員為我們提供了新的品牌字體規(guī)格,用到了自定義字體 Montserrat 和 Karla:

△ Jetchat 所使用的字體規(guī)格

我們首先使用 FontFamily 類聲明這些字體,該類將保存 Font 類的實例。我們可以使用字體資源 ID 和字體粗細構造 Font 類,然后使用 Typography 類聲明 Jetchat 字體樣式,并使用 TextStyle 類覆蓋每個文本樣式,包括我們的字體、字號、字體粗細等其他排版值。最后,同樣的,將 Typography 作為參數(shù)傳遞給 MaterialTheme:

val MontserratFontFamily = FontFamily ( 
    Font(R.font.montserrat_regular),
    Font(R.font montserrat_light, FontWeight Light),
    Font(R.font.montserrat_semibold, FontWeight. SemiBold)
)
 
val KarlaFontFamily = FontFamily (
    Font(R.font.karla_regular),
    Font(R.font.karla_bold, FontWeight. Bold)
)
 
val JetchatTypography = Typography( 
    bodyLarge = TextStyle(
        fontFamily = KarlaFontFamily,
        fontWeight = FontWeight. Normal,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.15.sp
    ),
 
    // titleMedium、labelSmall 等等
)
 
MaterialTheme (
    typography = JetchatTypography,
    // colorScheme、content
)

我們來看一下 Jetchat 對話界面,界面中的每個部分使用了 Jetchat 字體規(guī)格中的不同文本樣式。例如,消息中的聯(lián)系人和時間戳,分別使用了 titleMedium 和 labelSmall 樣式。它們通過 MaterialTheme.typography 表示訪問主題字體值。

△ 對話界面的字體設置
@Composable
fun Message(...) {
    …
    Text (style = MaterialTheme.typography.titleMedium, ...)
    …
    Text (style = MaterialTheme.typography.labelSmall, ...)
}

高度

在了解了 Material 3 主題相關的更新后,接下來讓我們看看 Material Design 另一個關鍵更新——高度。概括來說,Material 2 中使用陰影表示高度,而 Material 3 中改為使用色調(diào)顏色疊加層表示高度。這是一種區(qū)分容器和表面的新方式,增加色調(diào)高度會使色調(diào)變得更為突出。

在 Material 2 中高度疊加層是深色主題的一部分,在 Material 3 中也已更改為色調(diào)顏色疊加層。

△ M2 與 M3 中高度系統(tǒng)效果對比

我們以 Surface 組件為例,Surface 是用于支持大多數(shù) Material 組件的可組合項,現(xiàn)有的 Surface 可組合項實現(xiàn)的是 Material Design 2 的高度系統(tǒng)。在 Material Design 2 中 Surface 接收一個 elevation 參數(shù)并處理深色主題中的陰影和疊加層渲染。我們?yōu)?Material Design 3 引入了新版 Surface,它接受一個 tonalElevation 參數(shù),并會在淺色和深色主題中處理色調(diào)顏色疊加層渲染。讓我們看看前后有何不同:

△ Material 2 中的 Surface
△ Material 3 中的 Surface

組件更新

Material 3 對許多組件進行了更新,比如按鈕、應用欄、對話框、FAB 和導航組件。此類更新利用了新的 Material 3 主題設置值,并包含了對每個組件規(guī)范的最新更新。

△ Material 3 中更新的組件

例如 Material 2 中的 BottomNavigation。它符合 Material Design 2 規(guī)范,并接受 backgroundColor 和 elevation 等參數(shù)。在 Material 3 中該可組合項更名為 NavigationBar,它符合 Material Design 3 規(guī)范,其中的參數(shù)更改為 containerColor 和 tonalElevation,以更準確地反映各自的用途。

// Materail 2 中的 NavigationBar
import androidx.compose.material.BottomNavigation
 
@Composable
fun BottomNavigation (
    // M2 默認值
    backgroundColor: Color, 
    elevation: Dp,
    …
)
 
 
// Materail 3 中的 NavigationBar
import androidx.compose.material3.NavigationBar
 
@Composable
fun NavigationBar (
    // M3 默認值
    containerColor: Color, 
    tonalElevation: Dp,
    …
)
△ 更新前后的樣式改變

Compose Material 3 中的組件進行了很多更新,為了讓您全面了解所有的組件以及它們的實現(xiàn)方式,我們更新了 Compose Material Catalog 應用,并新增了 Material 3 部分。請在 AOSP 上查看 源代碼 并在 Google Play 中下載該應用

下面我們來看看 Jetchat 中的一個例子。在個人資料界面上有一個用于撰寫消息的擴展 FAB,該組件已從 Material 2 更新為 Material 3 版本。這是 Material 2 版本的一個簡單實現(xiàn),使用了 ExtendedFloatingActionButton 可組合項,內(nèi)部使用了 Icon 和 Text、可組合項以及自定義的 Primary 背景顏色。

import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Text
 
ExtendedFloatingActionButton(
    icon = { Icon(...) },
    text = { Text(...) },
    backgroundColor = MaterialTheme.colors.primary,
    ...
)

Material 3 對該組件的更新如這里所示,可組合項的依賴導入已更改為 Material 3,我們使用更名后的 containerColor 參數(shù)和 Material 3 配色方案中的 Tertiary 顏色。

import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
 
ExtendedFloatingActionButton(
    icon = { Icon(...) },
    text = { Text(...) },
    containerColor = MaterialTheme.colorScheme.tertiary,
    ...
)

視覺效果

Material You 的某些方面來自新的 Android 12 視覺樣式和系統(tǒng)界面,其中的兩個重要變化是波紋和滾動效果?,F(xiàn)在,波紋效果會在按下時使用細微的閃光照亮表面,滾動效果則會在滾動容器的邊緣使用拉伸效果。實現(xiàn)這些更改不需要額外的工作,在 Compose Foundation 1.1 及更高版本的滾動容器可組合項中拉伸滾動默認處于開啟狀態(tài);Android 12 上提供的閃光波紋適用于所有 Material 組件。

△ M2 與 M3 中的波紋效果
// 拉伸滾動
// 適用于 LazyColumn、Lazy Row、LazyVerticalGrid 等組件
// ComposeFoundation 1.1.0+ 可用
 
// 閃光波紋
// 適用于所有 Material 2 和 Material 3 組件
// Android 12+ 可用

與 Android View 的互操作性改進

與 Android 視圖的互操作性是使用 Compose 開發(fā)應用的一個重要部分,我們已經(jīng)在 Material 3 中進行了一些更新來支持這一點。MDC-AndroidCompose Theme Adapter 庫 是一款支持重用 Android XML 主題的 Material 組件,以方便我們在 Jetpack Compose 中設置主題。

現(xiàn)有的 MdcTheme 可組合項與 Material 2 XML 主題兼容,我們還引入了一個新的 Mdc3Theme 可組合項,它與 Material 3 XML 主題兼容。

△ MDC-AndroidCompose Theme Adapter 是 XML 主題與 MaterialTheme 之間的橋梁

尾聲

現(xiàn)在是在您的 Android 應用中試用 Compose Material 3 的好時機,我們準備了一系列資源來幫助您順利完成旅程。我們提供了新的關于 Compose Material 3 的 API 文檔,并在 Android Studio 中提供了新的 Empty Compose Activity 模板,其中包含有關 Material 3 的更新。此外,我們還更新了 Compose 中的主題設置 指南,以及在前面看到的 Jetchat 示例和 Compose Material Catalog 應用,以及 MDC-Android ComposeTheme Adapter 互操作性庫。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容