在 Compose for Wear OS 中從 Material 2.5 遷移至 Material 3

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,請按照這篇指南所述的相同方法操作,特別是:

依附元件

M3 的套件和版本與 M2.5 不同:

M2.5

implementation("androidx.wear.compose:compose-material:1.4.0")

M3

implementation("androidx.wear.compose:compose-material3:1.7.0-alpha01")

請前往 Wear Compose 質感設計 3 版本頁面查看 M3 的最新版本。

Wear Compose Foundation 程式庫 1.7.0-alpha01 版導入了一些新元件,這些元件專為搭配 Material 3 元件使用而設計。同樣地,在 Wear OS 6 (API 級別 36) 以上版本上執行時,SwipeDismissableNavHost Wear Compose Navigation 程式庫也會更新動畫。更新至 Wear Compose Material 3 版本時,建議一併更新 Wear Compose Foundation 和 Navigation 程式庫:

implementation("androidx.wear.compose:compose-foundation:1.7.0-alpha01")
implementation("androidx.wear.compose:compose-navigation:1.7.0-alpha01")

主題

在 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
Color 已重新命名為「ColorScheme
13 種顏色 28 種顏色
全新動態色彩主題
全新第三種顏色,讓您盡情揮灑創意

動態色彩主題

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 不同,且包含下列功能:

  • 九種全新文字樣式
  • 彈性字型,可自訂不同粗細、寬度和圓度的字體比例
  • 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
)

彈性字型

設計人員可使用彈性字型,為特定大小指定字型寬度和粗細。

文字樣式

M3 提供下列 TextStyle。各種 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 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」一文中的「形狀」參數對應做為起點。

形狀漸變

M3 推出形狀變形功能:形狀現在會因應互動而變形。

「形狀變形」行為適用於多種圓形按鈕,請參閱下列支援「形狀變形」的按鈕清單:

按鈕 形狀漸變功能
IconButton IconButtonDefaults.animatedShape 會在按下時為圖示按鈕加上動畫
IconToggleButton IconToggleButtonDefaults.animatedShape 會在按下時將圖示切換按鈕設為動畫,
IconToggleButtonDefaults.variantAnimatedShapes 則會在按下及勾選/取消勾選時將圖示切換按鈕設為動畫
TextButton TextButtonDefaults.animatedShape 會在按下時為文字按鈕加上動畫效果
TextToggleButton TextToggleButtonDefaults.animatedShapes 會在按下時為文字切換按鈕加上動畫效果,而 TextToggleButtonDefaults.variantAnimatedShapes 則會在按下及勾選/取消勾選時為文字切換按鈕加上動畫效果

元件和版面配置

M3 支援 M2.5 的大多數元件和版面配置。不過,部分 M3 元件和版面配置在 M2.5 中並不存在。此外,部分 M3 元件的變化版本比 M2.5 的同等元件還多。

雖然部分元件需要特別注意,但建議您以下列函式對應做為起點:

材質 2.5 Material 3
androidx.wear.compose.material.dialog.Alert androidx.wear.compose.material3.AlertDialog
androidx.wear.compose.material.Button androidx.wear.compose.material3.IconButtonandroidx.wear.compose.material3.TextButton
androidx.wear.compose.material.Card androidx.wear.compose.material3.Card
androidx.wear.compose.material.TitleCard androidx.wear.compose.material3.TitleCard
androidx.wear.compose.material.AppCard androidx.wear.compose.material3.AppCard
androidx.wear.compose.material.Checkbox 沒有 M3 同等項目,請遷移至 androidx.wear.compose.material3.CheckboxButtonandroidx.wear.compose.material3.SplitCheckboxButton
androidx.wear.compose.material.Chip androidx.wear.compose.material3.Button
androidx.wear.compose.material3.OutlinedButton
androidx.wear.compose.material3.FilledTonalButton
androidx.wear.compose.material3.ChildButton
androidx.wear.compose.material.CompactChip androidx.wear.compose.material3.CompactButton
androidx.wear.compose.material.InlineSlider androidx.wear.compose.material3.Slider
androidx.wear.compose.material.LocalContentAlpha() 已移除,因為 Material 3 中的 TextIcon 未使用
androidx.wear.compose.material.PositionIndicator androidx.wear.compose.material3.ScrollIndicator
androidx.wear.compose.material.RadioButton 沒有 M3 同等項目,請遷移至 androidx.wear.compose.material3.RadioButtonandroidx.wear.compose.material3.SplitRadioButton
androidx.wear.compose.material.SwipeToRevealCard androidx.wear.compose.material3.SwipeToReveal
androidx.wear.compose.material.SwipeToRevealChip androidx.wear.compose.material3.SwipeToReveal
android.wear.compose.material.Scaffold androidx.wear.compose.material3.AppScaffoldandroidx.wear.compose.material3.ScreenScaffold
androidx.wear.compose.material.SplitToggleChip 沒有對應的 M3 項目,請遷移至 androidx.wear.compose.material3.SplitCheckboxButtonandroidx.wear.compose.material3.SplitSwitchButtonandroidx.wear.compose.material3.SplitRadioButton
androidx.wear.compose.material.Switch 沒有 M3 同等項目,請遷移至 androidx.wear.compose.material3.SwitchButtonandroidx.wear.compose.material3.SplitSwitchButton
androidx.wear.compose.material.ToggleButton androidx.wear.compose.material3.IconToggleButtonandroidx.wear.compose.material3.TextToggleButton
androidx.wear.compose.material.ToggleChip androidx.wear.compose.material3.CheckboxButton
androidx.wear.compose.material3.RadioButton
androidx.wear.compose.material3.SwitchButton
androidx.wear.compose.material.Vignette 已移除,因為 Wear OS 的 Material 3 Expressive 設計未納入這項元素

以下列出所有 Material 3 元件:

Material 3 Material 2.5 同等元件 (如果不是 M3 的新元件)
androidx.wear.compose.material3.AlertDialog androidx.wear.compose.material.dialog.Alert
androidx.wear.compose.material3.AnimatedPage 新增
androidx.wear.compose.material3.AnimatedText 新增
androidx.wear.compose.material3.AppScaffold android.wear.compose.material.Scaffold (搭配 androidx.wear.compose.material3.ScreenScaffold )
androidx.wear.compose.material3.Button androidx.wear.compose.material.Chip
androidx.wear.compose.material3.ButtonGroup 新增
androidx.wear.compose.material3.Card androidx.wear.compose.material.Card
androidx.wear.compose.material3.CheckboxButton 具有核取方塊切換控制項的 androidx.wear.compose.material.ToggleChip
androidx.wear.compose.material3.ChildButton androidx.wear.compose.material.Chip (僅在不需要背景時)
androidx.wear.compose.material3.CircularProgressIndicator androidx.wear.compose.material.CircularProgressIndicator
androidx.wear.compose.material3.CompactButton androidx.wear.compose.material.CompactChip
androidx.wear.compose.material3.ConfirmationDialog androidx.wear.compose.material.dialog.Confirmation
androidx.wear.compose.material3.curvedText androidx.wear.compose.material.curvedText
androidx.wear.compose.material3.DatePicker 新增
androidx.wear.compose.material3.Dialog androidx.wear.compose.material.dialog.Dialog
androidx.wear.compose.material3.EdgeButton 新增
androidx.wear.compose.material3.FadingExpandingLabel 新增
androidx.wear.compose.material3.FilledTonalButton 需要色調按鈕背景時,請使用 androidx.wear.compose.material.Chip
androidx.wear.compose.material3.HorizontalPageIndicator androidx.wear.compose.material.HorizontalPageIndicator
androidx.wear.compose.material3.HorizontalPagerScaffold 新增
androidx.wear.compose.material3.Icon androidx.wear.compose.material.Icon
androidx.wear.compose.material3.IconButton androidx.wear.compose.material.Button
androidx.wear.compose.material3.IconToggleButton androidx.wear.compose.material.ToggleButton
androidx.wear.compose.material3.LevelIndicator 新增
androidx.wear.compose.material3.LinearProgressIndicator 新增
androidx.wear.compose.material3.ListHeader androidx.wear.compose.material.ListHeader
androidx.wear.compose.material3.ListSubHeader 新增
androidx.wear.compose.material3.MaterialTheme androidx.wear.compose.material.MaterialTheme
androidx.wear.compose.material3.OpenOnPhoneDialog 新增
androidx.wear.compose.material3.Picker androidx.wear.compose.material.Picker
androidx.wear.compose.material3.PickerGroup androidx.wear.compose.material.PickerGroup
androidx.wear.compose.material3.RadioButton 具有圓形按鈕切換控制項的 androidx.wear.compose.material.ToggleChip
androidx.wear.compose.material3.ScreenScaffold android.wear.compose.material.Scaffold (搭配 androidx.wear.compose.material3.AppScaffold)
androidx.wear.compose.material3.ScrollIndicator androidx.wear.compose.material.PositionIndicator
androidx.wear.compose.material3.scrollAway androidx.wear.compose.material.scrollAway
androidx.wear.compose.material3.SegmentedCircularProgressIndicator 新增
androidx.wear.compose.material3.Slider androidx.wear.compose.material.InlineSlider
androidx.wear.compose.material3.SplitRadioButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.SplitCheckboxButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.SplitSwitchButton androidx.wear.compose.material.SplitToggleChip
androidx.wear.compose.material3.Stepper androidx.wear.compose.material.Stepper
androidx.wear.compose.material3.SwipeToDismissBox androidx.wear.compose.material.SwipeToDismissBox
androidx.wear.compose.material3.SwipeToReveal androidx.wear.compose.material.SwipeToRevealCardandroidx.wear.compose.material.SwipeToRevealChip
androidx.wear.compose.material3.SwitchButton 具有切換開關控制項的 androidx.wear.compose.material.ToggleChip
androidx.wear.compose.material3.Text androidx.wear.compose.material.Text
androidx.wear.compose.material3.TextButton androidx.wear.compose.material.Button
androidx.wear.compose.material3.TextToggleButton androidx.wear.compose.material.ToggleButton
androidx.wear.compose.material3.TimeText androidx.wear.compose.material.TimeText
androidx.wear.compose.material3.VerticalPagerScaffold 新增

最後,我們列出 Wear Compose Foundation 程式庫中的一些相關元件:

Wear Compose Foundation 1.7.0-alpha01
androidx.wear.compose.foundation.hierarchicalFocusGroup 用於在應用程式中為可組合項加註,追蹤組合的有效部分並協調焦點。
androidx.wear.compose.foundation.pager.HorizontalPager 以 Compose Foundation 元件為基礎建構的水平捲動分頁檢視區塊,並針對 Wear 進行強化,以提升效能並符合 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 實作會為 TextmaxLinestextAlign 提供預設值。您可以在 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 推出新按鈕:EdgeButtonEdgeButton 提供 4 種尺寸:XS、S、M 和 L。EdgeButton 實作方式會根據大小提供 maxLines 的預設值,且可自訂。

如果您使用 TransformingLazyColumnScalingLazyColumn,請將 EdgeButton 傳遞至 ScreenScaffold,讓 EdgeButton 隨著捲動變形,而非新增為最終清單項目。請參閱下列程式碼,瞭解如何搭配使用 EdgeButtonScreenScaffoldTransformingLazyColumn

val state = rememberTransformingLazyColumnState()
ScreenScaffold(
    scrollState = state,
    contentPadding =
        rememberResponsiveColumnPadding(
            first = ColumnItemType.ListHeader
        ),
    edgeButton = {
        EdgeButton(
            onClick = { }
        ) {
            Text(stringResource(R.string.show))
        }
    }
){ contentPadding ->
    TransformingLazyColumn(state = state, contentPadding = contentPadding,){
        // additional code here
    }
}

Scaffold

M3 的 Scaffold 與 M2.5 不同。在 M3 中,AppScaffold 和新的 ScreenScaffold 可組合函式已取代 Scaffold。AppScaffoldScreenScaffold 會配置畫面結構,並協調 ScrollIndicatorTimeText 元件的轉場效果。

AppScaffold 可在應用程式內轉場期間 (例如滑動關閉),持續顯示靜態畫面元素 (例如 TimeText)。並為主要應用程式內容提供位置,通常由導覽元件 (例如 SwipeDismissableNavHost) 提供。

您要為每個 Activity 宣告一個 AppScaffold,並為每個畫面使用一個 ScreenScaffoldAppScaffold 會在畫面上新增預設的 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 padding = rememberResponsiveColumnPadding(
        first = ColumnItemType.BodyText
    )

    ScreenScaffold(
        scrollState = scrollState,
        contentPadding = padding
    ) { scaffoldPaddingValues ->
        // Screen content goes here
        // ...

如果您使用 HorizontalPagerHorizontalPagerIndicator,可以遷移至 HorizontalPagerScaffoldHorizontalPagerScaffold放置在 AppScaffold 內。AppScaffoldHorizontalPagerScaffold 會配置 Pager 的結構,並協調 HorizontalPageIndicatorTimeText 元件的轉場效果。

HorizontalPagerScaffold 預設會在畫面中央邊緣顯示 HorizontalPageIndicator,並根據 Pager 是否正在分頁,協調顯示和隱藏 TimeTextHorizontalPageIndicator,這取決於 PagerState

此外,還有新的 AnimatedPage 元件,可根據頁面在 Pager 中的位置,以縮放和半透明效果為頁面製作動畫。

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })
    val columnState = rememberTransformingLazyColumnState()
    val contentPadding = rememberResponsiveColumnPadding(
        first = ColumnItemType.ListHeader,
        last = ColumnItemType.BodyText,
    )
    HorizontalPagerScaffold(pagerState = pagerState) {
        HorizontalPager(
            state = pagerState,
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold(
                    scrollState = columnState,
                    contentPadding = contentPadding
                ) { contentPadding ->
                    TransformingLazyColumn(
                        state = columnState,
                        contentPadding = contentPadding
                    ) {
                        item {
                            ListHeader(
                                modifier = Modifier.fillMaxWidth()
                            ) {
                                Text(text = "Pager sample")
                            }
                        }
                        item {
                            if (page == 0) {
                                Text(text = "Page #$page. Swipe right")
                            }
                            else{
                                Text(text = "Page #$page. Swipe left and right")
                            }
                        }
                    }
                }

            }
        }
    }
}

最後,M3 導入了 VerticalPagerScaffold,其遵循的模式與 HorizontalPagerScaffold 相同:

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })

    VerticalPagerScaffold(pagerState = pagerState) {
        VerticalPager(
            state = pagerState
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold {
                    ///…
                }
            }
        }
    }
}

預留位置

M2.5 和 M3 之間有一些 API 變更。 Placeholder.PlaceholderDefaults 現在提供兩種修飾符:

如要瞭解 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 會更新 LocalSwipeToDismissBackgroundScrimColorLocalSwipeToDismissContentScrimColor

TransformingLazyColumn

TransformingLazyColumnwear.compose.lazy.foundation 的一部分,可支援在捲動期間縮放及變形清單項目的動畫,提升使用者體驗。強烈建議應用程式從 ScalingLazyColumn 遷移至 TransformingLazyColumn

ScalingLazyColumn 類似,它提供 rememberTransformingLazyColumnState() 來建立 TransformingLazyColumnState,並在組合中記住該 TransformingLazyColumnState

如要新增縮放和變形動畫,請在每個清單項目中加入下列項目:

  • Modifier.transformedHeight,可讓您使用 TransformationSpec 計算項目的轉換高度,除非需要進一步自訂,否則可以使用 rememberTransformationSpec()
  • A 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,請參閱下列其他資源。

範例

API 參考資料和原始碼

設計