Material 3 Expressive – это следующий этап развития Material Design. В ней обновлены темы, компоненты и функции персонализации, например динамические цвета.
В этом руководстве рассказывается, как перейти с библиотеки Jetpack Wear Compose Material 2.5 (androidx.wear.compose) на библиотеку Jetpack Wear Compose Material 3 (androidx.wear.compose.material3) для приложений.
Подходы
Чтобы перенести код приложения из M2.5 в M3, следуйте тому же подходу, который описан в руководстве по переносу Compose Material для телефонов, в частности:
- Не рекомендуется использовать обе версии в одном приложении в течение длительного времени.
- Больше не используйте библиотеки 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")
Последние версии M3 можно найти на странице выпусков Wear Compose.
В библиотеке Wear Compose Foundation версии 1.8.0-alpha02 появились новые компоненты, предназначенные для работы с компонентами Material 3.
Аналогично, у SwipeDismissableNavHost из библиотеки Wear Compose Navigation обновлена анимация при работе на Wear OS 6 (уровень API 36) или более поздней версии. При обновлении до 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")
Тема
В обеих версиях composable-функция темы называется 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 и включает следующие функции:
- Девять новых стилей текста.
- Гибкие шрифты, которые позволяют настраивать шкалы типов для различных весов, ширины и округлости
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 доступны следующие TextStyles: Они используются по умолчанию в различных компонентах M3.
| Параметры текста | TextStyle |
|---|---|
| Экран | displayLarge, displayMedium, displaySmall |
| Название | titleLarge, titleMedium, titleSmall |
| Label (Звукозаписывающая компания) | 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 )
В качестве отправной точки используйте сопоставление параметров Shapes из статьи Переход с Material 2 на Material 3 в Compose.
Преобразование фигур
В M3 добавлена функция Shape Morphing, которая позволяет фигурам менять форму в ответ на действия пользователя.
Преобразование формы доступно для ряда круглых кнопок, перечисленных ниже.
| Кнопки | Функция преобразования фигур |
|---|---|
IconButton |
IconButtonDefaults.animatedShapes анимирует кнопку со значком при нажатии. |
IconToggleButton |
IconToggleButtonDefaults.animatedShapes анимирует кнопку-переключатель со значком при нажатии, а IconToggleButtonDefaults.variantAnimatedShapes – при нажатии и установке или снятии флажка. |
TextButton |
TextButtonDefaults.animatedShapes анимирует текстовую кнопку при нажатии. |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes анимирует текстовый переключатель при нажатии, а TextToggleButtonDefaults.variantAnimatedShapes – при нажатии и установке/снятии флажка. |
Компоненты и макет
Большинство компонентов и макетов из M2.5 доступны в M3. Однако некоторые компоненты и макеты 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 | Используется для аннотирования composable-функций в приложении, чтобы отслеживать активную часть композиции и координировать фокус. |
| 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 доступен в четырех размерах: 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
Scaffold в M3 отличается от M2.5. В M3 AppScaffold и новая composable-функция ScreenScaffold заменили Scaffold. AppScaffold и ScreenScaffold определяют структуру экрана и координируют переходы компонентов ScrollIndicator и TimeText.
AppScaffold позволяет статическим элементам экрана, таким как TimeText, оставаться видимыми во время переходов в приложении, например при закрытии смахиванием. Он предоставляет слот для основного контента приложения, который обычно поставляется компонентом навигации, например SwipeDismissableNavHost.
Вы объявляете один AppScaffold для Activity и используете 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 в центре экрана и координирует показ и скрытие TimeText и HorizontalPageIndicator в зависимости от того, пролистывается ли Pager. Это определяется с помощью 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") } } } } } } }
Плейсхолдер
В API между M2.5 и M3 есть некоторые изменения. В 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, MaterialTheme M3 обновляет 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, ) } } } }
Полезные ссылки
Чтобы узнать больше о переходе с M2.5 на M3 в Compose, ознакомьтесь со следующими дополнительными ресурсами.