Material 3 Expressive to kolejna ewolucja Material Design. Obejmuje ona zaktualizowane motywy, komponenty i funkcje personalizacji, takie jak dynamiczny kolor.
Ten przewodnik skupia się na migracji z biblioteki Jetpack Wear Compose Material 2.5 (androidx.wear.compose) do biblioteki Jetpack Wear Compose Material 3 (androidx.wear.compose.material3) w przypadku aplikacji.
Podejścia
Aby przenieść kod aplikacji z M2.5 do M3, postępuj zgodnie z instrukcjami opisanymi w przewodniku po migracji do biblioteki Compose Material na telefonie, a w szczególności:
- Nie należy długoterminowo używać w jednej aplikacji zarówno M2.5, jak i M3.
- Nie należy już używać bibliotek Horologist Composables, Compose Layout ani Compose Material. Zamiast tego użyj komponentów w M3.
- Przyjmij podejście etapowe.
Zależności
M3 ma osobny pakiet i wersję niż M2.5:
M2,5
implementation("androidx.wear.compose:compose-material:1.4.0")
M3
implementation("androidx.wear.compose:compose-material3:1.6.0")
Najnowsze wersje M3 znajdziesz na stronie Wear Compose Material 3.
W bibliotece Wear Compose Foundation w wersji 1.6.0 wprowadziliśmy nowe komponenty, które są przeznaczone do współpracy z komponentami Material 3.
Podobnie SwipeDismissableNavHost z biblioteki Wear Compose Navigation ma zaktualizowaną animację, gdy jest uruchamiana na Wear OS 6 (API na poziomie 36) lub nowszym. Podczas aktualizacji do wersji Wear Compose Material 3 zalecamy też zaktualizowanie bibliotek Wear Compose Foundation i Navigation:
implementation("androidx.wear.compose:compose-foundation:1.6.0")
implementation("androidx.wear.compose:compose-navigation:1.6.0")
Motyw
W przypadku M2.5 i M3 funkcja kompozycyjna motywu ma nazwę MaterialTheme, ale pakiety importu i parametry różnią się. W M3 parametr Colors został zmieniony na ColorScheme, a do implementacji przejść wprowadzono parametr 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*/ } )
Kolor
System kolorów w M3 znacznie różni się od tego w M2.5. Liczba parametrów koloru wzrosła, mają one różne nazwy i inaczej mapują się na komponenty M3. W przypadku Compose dotyczy to klas M2.5 Colors, M3 ColorScheme i powiązanych funkcji:
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 )
W tej tabeli opisano najważniejsze różnice między M2.5 i M3:
| M2,5 | M3 |
|---|---|
Color |
Zmieniono nazwę na ColorScheme |
| 13 kolorów | 28 kolorów |
| Nie dotyczy | Nowe dynamiczne motywy kolorystyczne |
| Nie dotyczy | Nowe kolory trzeciorzędowe, które pozwolą Ci wyrazić więcej |
Dynamiczne motywy kolorystyczne
Nową funkcją M3 jest dynamiczne kolorowanie. Jeśli użytkownicy zmienią kolory tarczy zegarka, kolory w interfejsie zmienią się tak, aby do nich pasować.
Użyj funkcji dynamicColorScheme, aby wdrożyć dynamiczny schemat kolorów, i podaj defaultColorScheme jako rezerwę na wypadek, gdyby dynamiczny schemat kolorów był niedostępny.
@Composable fun myApp() { val dynamicColorScheme = dynamicColorScheme(LocalContext.current) MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {} } internal val myBrandColors: ColorScheme = ColorScheme( /* Specify colors here */)
Typografia
System typografii w M3 różni się od tego w M2.5 i obejmuje te funkcje:
- 9 nowych stylów tekstu
- czcionki elastyczne, które umożliwiają dostosowywanie skal typów do różnych grubości, szerokości i zaokrągleń;
AnimatedText, który używa elastycznych czcionek;
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 )
Czcionki elastyczne
Czcionki elastyczne umożliwiają projektantom określanie szerokości i grubości znaków dla konkretnych rozmiarów.
Style tekstu
W M3 dostępne są te TextStyles: Są one domyślnie używane przez różne komponenty M3.
| Typografia | TextStyle |
|---|---|
| Wyświetlacz | displayLarge, displayMedium, displaySmall |
| Tytuł | titleLarge, titleMedium, titleSmall |
| Etykieta | labelLarge, labelMedium, labelSmall |
| Treść | bodyLarge, bodyMedium, bodySmall, bodyExtraSmall |
| Cyfry | numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall |
| Łuk | arcLarge, arcMedium, arcSmall |
Kształt
System kształtów w M3 różni się od tego w M2.5. Liczba parametrów kształtu wzrosła, mają one inne nazwy i inaczej są mapowane na komponenty M3. Dostępne są te rozmiary kształtów:
- Bardzo mały
- Mały
- średni,
- Duży
- Bardzo duży
W Compose dotyczy to klas M2 Shapes i 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 )
Jako punkt początkowy użyj mapowania parametrów kształtów z artykułu Migracja z Material 2 na Material 3 w Compose.
Przekształcanie kształtu
W M3 wprowadziliśmy zmianę kształtu: kształty zmieniają się teraz w odpowiedzi na interakcje.
Funkcja zmiany kształtu jest dostępna w przypadku kilku okrągłych przycisków. Poniżej znajdziesz listę przycisków, które obsługują zmianę kształtu:
| Przyciski | Funkcja przekształcania kształtu |
|---|---|
IconButton |
IconButtonDefaults.animatedShape animuje przycisk ikony po naciśnięciu. |
IconToggleButton |
IconToggleButtonDefaults.animatedShape animuje przycisk przełączania ikony po naciśnięciu, a IconToggleButtonDefaults.variantAnimatedShapes animuje przycisk przełączania ikony po naciśnięciu i zaznaczeniu/odznaczeniu. |
TextButton |
TextButtonDefaults.animatedShape animuje przycisk tekstowy po naciśnięciu. |
TextToggleButton |
TextToggleButtonDefaults.animatedShapes animuje przełącznik tekstowy po naciśnięciu, a TextToggleButtonDefaults.variantAnimatedShapes animuje przełącznik tekstowy po naciśnięciu oraz zaznaczeniu lub odznaczeniu. |
Komponenty i układ
Większość komponentów i układów z M2.5 jest dostępna w M3. Niektóre komponenty i układy M3 nie występowały jednak w M2.5. Ponadto niektóre komponenty M3 mają więcej odmian niż ich odpowiedniki w M2.5.
Niektóre komponenty wymagają szczególnej uwagi, ale jako punkt początkowy zalecamy te mapowania funkcji:
Oto pełna lista wszystkich komponentów Material 3:
Na koniec lista niektórych komponentów z biblioteki Wear Compose Foundation:
| Wear Compose Foundation 1.6.0 | |
|---|---|
| androidx.wear.compose.foundation.hierarchicalFocusGroup | Służy do dodawania adnotacji do funkcji kompozycyjnych w aplikacji, aby śledzić aktywną część kompozycji i koordynować fokus. |
| androidx.wear.compose.foundation.pager.HorizontalPager | Przewijany w poziomie pager oparty na komponentach Compose Foundation z ulepszeniami dostosowanymi do Wear, które zwiększają wydajność i zgodność z wytycznymi Wear OS. |
| androidx.wear.compose.foundation.pager.VerticalPager | Przewijany pionowo pager oparty na komponentach Compose Foundation z ulepszeniami dostosowanymi do Wear, które zwiększają wydajność i zgodność z wytycznymi Wear OS. |
| androidx.wear.compose.foundation.lazy.TransformingLazyColumn | Można go używać zamiast ScalingLazyColumn, aby dodać do każdego elementu efekty przekształcenia podczas przewijania. |
Przyciski
Przyciski w M3 różnią się od przycisków w M2.5. Element M2.5 Chip został zastąpiony elementem Button. Implementacja Button zapewnia domyślne wartości parametrów Text
maxLines i textAlign. Te wartości domyślne można zastąpić w elemencie 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 zawiera też nowe warianty przycisków. Zapoznaj się z nimi w omówieniu dokumentacji API Compose Material 3.
W M3 wprowadziliśmy nowy przycisk: EdgeButton. EdgeButton jest dostępny w 4 rozmiarach: bardzo małym, małym, średnim i dużym. EdgeButton
implementacja podaje domyślną wartość parametru maxLines w zależności od rozmiaru,
którą można dostosować.
Jeśli używasz TransformingLazyColumn lub ScalingLazyColumn, przekaż EdgeButton do ScreenScaffold, aby zmieniał kształt podczas przewijania, zamiast dodawać EdgeButton jako ostatni element listy. Zapoznaj się z poniższym kodem, aby sprawdzić, jak używać funkcji EdgeButton z usługami ScreenScaffold i TransformingLazyColumn.
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
Scaffold w M3 różni się od M2.5. W M3 komponent AppScaffold i nowy komponent ScreenScaffold zastąpiły komponent Scaffold. AppScaffold i ScreenScaffold określają strukturę ekranu i koordynują przejścia komponentów ScrollIndicator i TimeText.
AppScaffold umożliwia pozostawienie widocznych statycznych elementów ekranu, takich jak TimeText, podczas przejść w aplikacji, np. podczas zamykania aplikacji gestem. Zapewnia miejsce na główną zawartość aplikacji, która zwykle jest dostarczana przez komponent nawigacyjny, taki jak SwipeDismissableNavHost
Deklarujesz 1 AppScaffold dla Activity i używasz ScreenScaffold dla każdego ekranu.
AppScaffold dodaje do ekranów domyślny TimeTextkomponent. Możesz ją zastąpić, jeśli chcesz ją dostosować, używając parametru 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 // ...
Jeśli używasz HorizontalPager z HorizontalPagerIndicator, możesz przejść na HorizontalPagerScaffold. Element HorizontalPagerScaffold jest umieszczony w AppScaffold. AppScaffold i HorizontalPagerScaffold określają strukturę komponentu Pager i koordynują przejścia komponentów HorizontalPageIndicator i TimeText.
HorizontalPagerScaffold domyślnie wyświetla HorizontalPageIndicator na środku ekranu i koordynuje wyświetlanie i ukrywanie TimeText i HorizontalPageIndicator w zależności od tego, czy Pager jest stronicowany. Określa to PagerState.
Jest też nowy komponent AnimatedPage, który animuje stronę w komponencie Pager za pomocą efektu skalowania i przyciemniania w zależności od jej pozycji.
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") } } } } } } } }
W końcu M3 wprowadza VerticalPagerScaffold, które ma taki sam wzór jak HorizontalPagerScaffold:
AppScaffold { val pagerState = rememberPagerState(pageCount = { 10 }) VerticalPagerScaffold(pagerState = pagerState) { VerticalPager( state = pagerState ) { page -> AnimatedPage(pageIndex = page, pagerState = pagerState) { ScreenScaffold { ///… } } } } }
Obiekt zastępczy
Między wersjami M2.5 i M3 interfejsu API występują pewne różnice.
Placeholder.PlaceholderDefaults udostępnia teraz 2 modyfikatory:
Modifier.placeholder, który jest rysowany zamiast treści, które nie zostały jeszcze wczytane.- Efekt połysku elementu zastępczego
Modifier.placeholderShimmer, który zapewnia efekt połysku elementu zastępczego działający w pętli animacji podczas oczekiwania na załadowanie danych.
Dodatkowe zmiany w komponencie Placeholder znajdziesz w tabeli poniżej.
| M2,5 | M3 |
|---|---|
PlaceholderState.startPlaceholderAnimation |
został usunięty. |
PlaceholderState.placeholderProgression |
został usunięty. |
PlaceholderState.isShowContent |
Zmieniono nazwę na !PlaceholderState.isVisible |
PlaceholderState.isWipeOff |
został usunięty. |
PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush |
został usunięty. |
PlaceholderDefaults.placeholderBackgroundBrush |
został usunięty. |
PlaceholderDefaults.placeholderChipColors |
został usunięty. |
SwipeDismissableNavHost
SwipeDismissableNavHost jest częścią usługi wear.compose.navigation. Gdy ten komponent jest używany z M3, M3 MaterialTheme aktualizuje LocalSwipeToDismissBackgroundScrimColor i LocalSwipeToDismissContentScrimColor.
TransformingLazyColumn
TransformingLazyColumn jest częścią wear.compose.lazy.foundation i dodaje obsługę animacji skalowania i przekształcania elementów listy podczas przewijania, co zwiększa komfort użytkowania. Zdecydowanie zalecamy migrację aplikacji z ScalingLazyColumn do TransformingLazyColumn.
Podobnie jak ScalingLazyColumn, udostępnia rememberTransformingLazyColumnState() do tworzenia TransformingLazyColumnState, który jest zapamiętywany w różnych kompozycjach.
Aby dodać animacje skalowania i przekształcania, dodaj do każdego elementu listy te elementy:
Modifier.transformedHeight, która umożliwia obliczanie przekształconej wysokości elementów za pomocąTransformationSpec. Możesz użyćrememberTransformationSpec(), chyba że potrzebujesz dalszej personalizacji.SurfaceTransformation
Aby sprawdzić, czy dopełnienie u góry i u dołu listy jest prawidłowe, użyj modyfikatora 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, ) } } } }
Przydatne linki
Więcej informacji o migracji z M2.5 do M3 w Compose znajdziesz w tych materiałach.