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 на телефоне, в частности:
- Не рекомендуется одновременно использовать 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-alpha01")
Последние версии M3 можно найти на странице выпусков Wear Compose.
В библиотеке Wear Compose Foundation версии 1.8.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.8.0-alpha01")
implementation("androidx.wear.compose:compose-navigation:1.8.0-alpha01")
Тема
В версиях M2.5 и M3 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 )
Шрифты Flex
Шрифты Flex позволяют дизайнерам задавать ширину и толщину шрифта для определенных размеров.
Стили текста
В 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 )
Используйте сопоставление параметров фигур из статьи Переход с Material 2 на Material 3 в Compose в качестве отправной точки.
Морфинг фигур
В M3 появилась функция "Преобразование фигур": теперь фигуры меняются в ответ на действия пользователя.
Поведение "Преобразующаяся фигура" доступно в качестве варианта для ряда круглых кнопок. Ниже приведен список кнопок, поддерживающих это поведение:
| Кнопки | Функция преобразования фигур |
|---|---|
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-alpha01 | |
|---|---|
| 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 OS, которые повышают производительность и соответствие рекомендациям 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
В M3 используется другой каркас, чем в M2.5. В M3 вместо Scaffold используются AppScaffold и новый компонент ScreenScaffold. 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, ознакомьтесь со следующими дополнительными ресурсами.