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 中的一项新功能。如果用户更改表盘颜色,界面中的颜色也会随之更改。
使用 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,该应用使用 Flex 字体
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 字体,设计师可以为特定字号指定字体宽度和粗细。
文本样式
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.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 中的形状参数映射。
形状渐变
M3 引入了形状渐变:形状现在会根据互动而渐变。
形状渐变行为可作为多种圆形按钮的变体,请参阅以下支持形状渐变的按钮列表:
| 按钮 | 形状渐变功能 |
|---|---|
IconButton |
IconButtonDefaults.animatedShapes 会在按下时为图标按钮添加动画效果 |
IconToggleButton |
IconToggleButtonDefaults.animatedShapes 会在按下时为图标切换按钮添加动画效果,而 IconToggleButtonDefaults.variantAnimatedShapes 会在按下和选中/取消选中时为图标切换按钮添加动画效果 |
TextButton |
TextButtonDefaults.animatedShapes 会在按下文本按钮时为其添加动画效果 |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes 会在按下时为文字切换按钮添加动画效果,而 TextToggleButtonDefaults.variantAnimatedShapes 会在按下和选中/取消选中时为文字切换按钮添加动画效果 |
组件和布局
M2.5 中的大多数组件和布局在 M3 中均具有可用性。不过,M2.5 中没有一些 M3 组件和布局。此外,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 进行了增强,以提升性能并遵循 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 种不同尺寸:超小号、小号、中号和大号。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 采用与 M2.5 不同的 Scaffold。在 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 // ...
如果您将 HorizontalPager 与 HorizontalPageIndicator 搭配使用,则可以迁移到 HorizontalPagerScaffold。HorizontalPagerScaffold 放置在 AppScaffold 中。AppScaffold 和 HorizontalPagerScaffold 会布局 Pager 的结构,并协调 HorizontalPageIndicator 和 TimeText 组件的转换。
HorizontalPagerScaffold 默认会在屏幕中心位置显示 HorizontalPageIndicator,并根据 Pager 是否正在分页(由 PagerState 确定)来协调显示和隐藏 TimeText 和 HorizontalPageIndicator。
此外,还有一个新的 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,请参阅下面列出的其他资源。