Material 3 Expressive 是新一代的 Material Design,提供更新後的主題設定、元件,以及動態色彩等個人化功能。
本指南主要說明如何將應用程式從 Wear Compose Material 2.5 (androidx.wear.compose) Jetpack 程式庫,遷移至 Wear Compose Material 3 (androidx.wear.compose.material3) Jetpack 程式庫。
做法
如要將應用程式程式碼從 M2.5 遷移至 M3,請按照 Compose Material 遷移手機指南所述的方法操作,特別是:
- 請勿在單一應用程式中長期同時使用 M2.5 和 M3。
- 請勿再使用 Horologist Composables、Compose Layout 或 Compose Material 程式庫。請改用 M3 中的元件。
- 採取階段式做法。
依附元件
M3 的套件和版本與 M2.5 不同:
M2.5
implementation("androidx.wear.compose:compose-material:1.4.0")
M3
implementation("androidx.wear.compose:compose-material3:1.8.0-alpha02")
請前往 Wear Compose 版本頁面查看 M3 的最新版本。
Wear Compose Foundation 程式庫 1.8.0-alpha02 版推出了一些新元件,可與 Material 3 元件搭配使用。同樣地,在 Wear OS 6 (API 級別 36) 以上版本中,Wear Compose Navigation 程式庫的 SwipeDismissableNavHost 也有更新動畫。更新至 Wear Compose Material 3 版本時,建議您一併更新 Wear Compose Foundation 和 Navigation 程式庫:
implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha02")
implementation("androidx.wear.compose:compose-navigation:1.8.0-alpha02")
主題
在 M2.5 和 M3 中,主題可組合項的名稱都是 MaterialTheme,但匯入套件和參數並不相同。在 M3 中,Colors 參數已重新命名為 ColorScheme,並導入 MotionScheme 來實作轉場效果。
M2.5
import androidx.wear.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes,
content = content
)
M3
import androidx.wear.compose.material3.MaterialTheme // ... MaterialTheme( colorScheme = ColorScheme(), typography = Typography(), shapes = Shapes(), motionScheme = MotionScheme.standard(), content = { /*content here*/ } )
顏色
M3 的色彩系統與 M2.5 有明顯差異。顏色參數的數量有所增加,名稱也不同,且分別對應至 M3 元件。在 Compose 中,這適用於 M2.5 Colors 類別、M3 ColorScheme 類別和相關函式:
M2.5
import androidx.wear.compose.material.Colors
val appColorScheme: Colors = Colors(
// M2.5 Color parameters
)
M3
import androidx.wear.compose.material3.ColorScheme // ... val appColorScheme: ColorScheme = ColorScheme( // M3 ColorScheme parameters )
下表說明 M2.5 和 M3 的主要差異:
| M2.5 | M3 |
|---|---|
Colors |
已重新命名為 ColorScheme |
| 13 種顏色 | 29 種顏色 |
| 不適用 | 全新動態色彩主題 |
| 不適用 | 新增第三種顏色,展現更多風格 |
動態色彩主題
M3 的其中一項新功能是動態色彩主題設定。如果使用者變更錶面顏色,UI 中的顏色也會隨之變更。
使用 dynamicColorScheme 函式實作動態色彩配置,並提供 defaultColorScheme 做為備用方案,以防動態色彩配置無法使用。
@Composable fun myApp() { val dynamicColorScheme = dynamicColorScheme(LocalContext.current) MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {} } internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)
字體排版
M3 的字體排版系統與 M2.5 不同,包含下列功能:
- 九種全新文字樣式
- Flex 字型,可自訂不同粗細、寬度和圓角的字型比例
AnimatedText,使用彈性字型
M2.5
import androidx.wear.compose.material.Typography
val Typography = Typography(
// M2.5 TextStyle parameters
)
M3
import androidx.wear.compose.material3.Typography val Typography = Typography( // M3 TextStyle parameters )
Flex 字型
Flex Fonts 可讓設計師指定特定大小的字型寬度和粗細。
文字樣式
M3 提供下列 TextStyles。各種 M3 元件預設會採用這些顏色。
| 字體排版 | TextStyle |
|---|---|
| 螢幕 | displayLarge、displayMedium、displaySmall |
| 標題 | titleLarge、titleMedium、titleSmall |
| 標籤 | labelLarge、labelMedium、labelSmall |
| 內文 | bodyLarge、bodyMedium、bodySmall、bodyExtraSmall |
| 數字 | numeralExtraLarge、numeralLarge、numeralMedium、numeralSmall、numeralExtraSmall |
| 弧形 | arcLarge、arcMedium、arcSmall |
圖案
M3 的形狀系統與 M2.5 不同。形狀參數的數量有所增加,名稱也不同,且分別對應至 M3 元件。可用的形狀大小如下:
- 特小
- 小
- 中
- 大
- 特大
在 Compose 中,這適用於 M2.5 Shapes 類別和 M3 Shapes 類別:
M2.5
import androidx.wear.compose.material.Shapes
val Shapes = Shapes(
// M2.5 Shapes parameters
)
M3
import androidx.wear.compose.material3.Shapes val Shapes = Shapes( // M3 Shapes parameters )
請先參考「在 Compose 中從 Material 2 遷移至 Material 3」一文中的 Shapes 參數對應。
形狀變形
M3 推出形狀變形功能:形狀現在會根據互動變形。
形狀變形行為可做為多個圓形按鈕的變化版本,請參閱下列支援形狀變形的按鈕清單:
| 按鈕 | 形狀變形函式 |
|---|---|
IconButton |
IconButtonDefaults.animatedShapes 會在按下時為圖示按鈕加上動畫 |
IconToggleButton |
IconToggleButtonDefaults.animatedShapes 會在按下圖示切換鈕時播放動畫, IconToggleButtonDefaults.variantAnimatedShapes 則會在按下及勾選/取消勾選圖示切換鈕時播放動畫 |
TextButton |
TextButtonDefaults.animatedShapes 會在按下文字按鈕時顯示動畫 |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes 會在按下時為文字切換按鈕加上動畫效果,TextToggleButtonDefaults.variantAnimatedShapes 則會在按下和勾選/取消勾選時為文字切換按鈕加上動畫效果 |
元件和版面配置
M3 支援 M2.5 的大多數元件和版面配置。不過,部分 M3 元件和版面配置在 M2.5 中並不存在。此外,部分 M3 元件的變化版本比 M2.5 的同等元件還多。
雖然部分元件需要特別注意,但建議您以下列函式對應做為起點:
以下列出常見的 Material 3 元件及其對應的 Material 2.5 元件:
最後,列出 Wear Compose Foundation 程式庫中的一些相關元件:
| Wear Compose Foundation 1.8.0-alpha02 | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | 用於為應用程式中的可組合項加上註解,追蹤組合中的有效部分並協調焦點。 |
| androidx.wear.compose.foundation.pager.HorizontalPager | 水平捲動翻頁元素,以 Compose Foundation 元件為基礎建構,並針對 Wear OS 進行強化,可提升效能並遵循 Wear OS 指南。 |
| androidx.wear.compose.foundation.pager.VerticalPager | 垂直捲動翻頁元素,以 Compose Foundation 元件為基礎建構,並針對 Wear 進行強化,可提升效能並遵循 Wear OS 指南。 |
| androidx.wear.compose.foundation.lazy.TransformingLazyColumn | 可用來取代 ScalingLazyColumn,為每個項目新增捲動轉換效果。 |
按鈕
M3 的按鈕與 M2.5 不同。M2.5 晶片已由按鈕取代。Button 實作會為 Text、maxLines 和 textAlign 提供預設值。您可以在 Text 元素中覆寫這些預設值。
M2.5
import androidx.wear.compose.material.Chip
//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)
M3
//M3 Buttons Button(onClick = { }){} CompactButton(onClick = { }){} IconButton(onClick = { }){} TextButton(onClick = { }){}
M3 也提供新的按鈕變化版本。詳情請參閱 Compose Material 3 API 參考資料總覽。
M3 推出新按鈕:EdgeButton。EdgeButton 有 4 種尺寸:XS、S、M 和 L。EdgeButton 實作會根據可自訂的大小,為 maxLines 提供預設值。
如果您使用 TransformingLazyColumn 或 ScalingLazyColumn,請將 EdgeButton 傳遞至 ScreenScaffold,使其變形,並隨著捲動變更形狀,而不是將 EdgeButton 新增為最終清單項目。請參閱下列程式碼,瞭解如何搭配使用 EdgeButton 與 ScreenScaffold 和 TransformingLazyColumn。
val state = rememberTransformingLazyColumnState() ScreenScaffold( scrollState = state, edgeButton = { EdgeButton( onClick = { }, modifier = Modifier.scrollable( state, orientation = Orientation.Vertical, reverseDirection = true, // Apply overscroll to the EdgeButton for proper scrolling behavior. overscrollEffect = rememberOverscrollEffect(), ), ) { Text(stringResource(R.string.show)) } }, ) { contentPadding -> TransformingLazyColumn(state = state, contentPadding = contentPadding) { // additional code here // ... } }
Scaffold
M3 的 Scaffold 與 M2.5 不同。在 M3 中,AppScaffold 和新的 ScreenScaffold 可組合項已取代 Scaffold。AppScaffold 和 ScreenScaffold 會配置畫面結構,並協調 ScrollIndicator 和 TimeText 元件的轉場效果。
AppScaffold 可在應用程式內轉場期間 (例如滑動關閉),持續顯示靜態畫面元素 (例如 TimeText)。它提供主要應用程式內容的版位,通常由導覽元件 (例如 SwipeDismissableNavHost) 提供
您需要為 Activity 宣告一個 AppScaffold,並為每個畫面使用 ScreenScaffold。AppScaffold 會在畫面上新增預設的 TimeText 元件。如要自訂,可以使用 timeText 參數覆寫。
M2.5
import androidx.wear.compose.material.Scaffold
Scaffold {...}
M3
AppScaffold { val navController = rememberSwipeDismissableNavController() SwipeDismissableNavHost( navController = navController, startDestination = "message_list" ) { composable("message_list") { MessageList(onMessageClick = { id -> navController.navigate("message_detail/$id") }) } composable("message_detail/{id}") { MessageDetail(id = it.arguments?.getString("id")!!) } } } } // Implementation of one of the screens in the navigation @Composable fun MessageDetail(id: String) { // .. Screen level content goes here val scrollState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = scrollState, ) { contentPadding -> // Screen content goes here // ...
如果您搭配 HorizontalPageIndicator 使用 HorizontalPager,可以遷移至 HorizontalPagerScaffold。HorizontalPagerScaffold 位於 AppScaffold 內。AppScaffold 和 HorizontalPagerScaffold 會配置 Pager 的結構,並協調 HorizontalPageIndicator 和 TimeText 元件的轉場效果。
HorizontalPagerScaffold 預設會在畫面中央邊緣顯示 HorizontalPageIndicator,並根據 Pager 是否正在分頁,協調顯示和隱藏 TimeText 和 HorizontalPageIndicator,這由 PagerState 決定。
此外,我們也推出新的 AnimatedPage 元件,可根據位置,以縮放和遮罩效果為 Pager 中的頁面加上動畫。
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) HorizontalPagerScaffold(pagerState = pagerState) { HorizontalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( ListHeaderDefaults.minimumTopListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(text = "Pager sample") } } item { Card( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { if (page == 0) { Text(text = "Page #$page. Swipe right") } else { Text(text = "Page #$page. Swipe left and right") } } } } } } } } }
最後,M3 導入了 VerticalPagerScaffold,其模式與 HorizontalPagerScaffold 相同:
@Composable fun VerticalPagerScaffoldSample() { AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState, flingBehavior = PagerScaffoldDefaults.snapWithSpringFlingBehavior( state = pagerState ), ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { Text(text = "Page #$page") Spacer(modifier = Modifier.height(8.dp)) Text(text = "Swipe up and down") } } } } } } }
預留位置
M2.5 和 M3 之間有一些 API 變更。M3 提供兩種預留位置修飾符:
Modifier.placeholder:在內容尚未載入時繪製- 預留位置閃爍效果
Modifier.placeholderShimmer,在等待資料載入時,提供在動畫迴圈中執行的預留位置閃爍效果。
請參閱下表,瞭解 Placeholder 元件的其他異動。
| M2.5 | M3 |
|---|---|
PlaceholderState.startPlaceholderAnimation |
已移除 |
PlaceholderState.placeholderProgression |
已移除 |
PlaceholderState.isShowContent |
由 PlaceholderState.isVisible 取代 (反向布林值) |
PlaceholderState.isWipeOff |
已移除 |
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush |
已移除 |
PlaceholderDefaults.placeholderBackgroundBrush |
已移除 |
PlaceholderDefaults.placeholderChipColors |
已移除 |
SwipeDismissableNavHost
SwipeDismissableNavHost 是 wear.compose.navigation 的一部分。如果這個元件與 M3 搭配使用,M3 MaterialTheme 會更新 LocalSwipeToDismissBackgroundScrimColor 和 LocalSwipeToDismissContentScrimColor。
TransformingLazyColumn
TransformingLazyColumn 是 androidx.wear.compose.foundation.lazy 的一部分,可支援在捲動時縮放及變換清單項目動畫,提升使用者體驗。強烈建議應用程式從 ScalingLazyColumn 遷移至 TransformingLazyColumn。
與 ScalingLazyColumn 類似,它提供 rememberTransformingLazyColumnState(),可建立在不同組合中記住的 TransformingLazyColumnState。
如要新增縮放和變形動畫,請在每個清單項目中加入以下內容:
Modifier.transformedHeight:可讓您使用TransformationSpec計算項目的轉換高度,除非需要進一步自訂,否則可以使用rememberTransformationSpec()。SurfaceTransformation
如要確認清單頂端和底部的邊框間距是否正確,請使用 minimumVerticalContentPadding 修飾符。
val columnState = rememberTransformingLazyColumnState() val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding ) { item { ListHeader( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ListHeaderDefaults.minimumTopListContentPadding), transformation = SurfaceTransformation(transformationSpec) ) { Text(text = "Header") } } // ... other items item { Button( modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding(ButtonDefaults.minimumVerticalListContentPadding), transformation = SurfaceTransformation(transformationSpec), onClick = { /* ... */ }, icon = { Icon( imageVector = Icons.Default.Build, contentDescription = "build", ) }, ) { Text( text = "Build", maxLines = 1, overflow = TextOverflow.Ellipsis, ) } } } }
實用連結
如要進一步瞭解如何在 Compose 中從 M2.5 遷移至 M3,請參閱下列其他資源。