Material Design 3 to kolejna wersja Material Design. Obejmuje ona zaktualizowane motywy, komponenty i funkcje personalizacji Material You, takie jak dynamiczne kolory. Jest to aktualizacja Material Design 2, która jest spójna z nowym stylem wizualnym i interfejsem systemu w Androidzie 12 lub nowszym.
Ten przewodnik dotyczy migracji z biblioteki Jetpack Compose Material (androidx.compose.material) do biblioteki Jetpack Compose Material 3 (androidx.compose.material3).
Podejścia
Ogólnie nie należy długotrwale używać w jednej aplikacji zarówno M2, jak i M3. Wynika to z tego, że oba systemy projektowania i odpowiednie biblioteki różnią się znacznie pod względem projektowania UX/UI i implementacji Compose.
Aplikacja może korzystać z systemu projektowania, np. utworzonego w programie Figma. W takich przypadkach zdecydowanie zalecamy, aby Ty lub Twój zespół projektantów przeprowadzili migrację z M2 do M3 przed rozpoczęciem migracji w Compose. Nie ma sensu przekształcanie aplikacji w M3, jeśli jej projekt UX/UI jest oparty na M2.
Ponadto podejście do migracji powinno się różnić w zależności od rozmiaru, złożoności i projektu interfejsu użytkownika aplikacji. Pozwoli to zminimalizować wpływ na kod źródłowy. Migrację należy przeprowadzić etapami.
Kiedy przenosić
Migrację należy rozpocząć jak najszybciej. Należy jednak wziąć pod uwagę, czy Twoja aplikacja jest w stanie w pełni przejść z M2 na M3. Istnieje kilka scenariuszy związanych z blokowaniem, które warto sprawdzić, zanim zaczniesz:
Scenariusz | Zalecane działania |
---|---|
Brak blokujących | Rozpocznij migrację w etapach |
Komponent z M2 nie jest jeszcze dostępny w M3. Zobacz sekcję Komponenty i układy poniżej. | Rozpocznij migrację stopniową |
Ty lub Twój zespół projektantów nie przeprowadziliście migracji systemu projektowania aplikacji z M2 na M3 | Przeniesienie systemu projektowania z M2 do M3, a następnie rozpoczęcie migracji etapowej |
Nawet jeśli powyższe scenariusze Cię dotyczą, przed zatwierdzeniem i opublikowaniem aktualizacji aplikacji powinieneś przejść przez migrację w kilku etapach. W takich przypadkach możesz używać jednocześnie wersji M2 i M3, a podczas migracji do wersji M3 stopniowo wycofywać wersję M2.
Metoda stopniowa
Ogólne etapy migracji w etapach:
- Dodaj zależność M3 obok zależności M2.
- Dodaj wersje M3 motywów swojej aplikacji razem z wersjami M2 motywów aplikacji.
- Przenieś poszczególne moduły, ekrany lub elementy kompozycyjne do wersji M3 w zależności od rozmiaru i złożoności aplikacji (szczegóły znajdziesz w sekcjach poniżej).
- Po zakończeniu migracji usuń wersje M2 motywów aplikacji.
- Usuń zależność M2.
Zależności
M3 ma oddzielny pakiet i wersję od M2:
M2
implementation "androidx.compose.material:material:$m2-version"
M3
implementation "androidx.compose.material3:material3:$m3-version"
Najnowsze wersje M3 znajdziesz na stronie wersji Compose Material 3.
Pozostałe zależności komponentów spoza głównych bibliotek M2 i M3 nie uległy zmianie. Używają one pakietów i wersji M2 i M3, ale nie ma to wpływu na migrację. Można ich używać w M3 bez zmian:
Biblioteka | Pakiet i wersja |
---|---|
Tworzenie ikon Material Design | androidx.compose.material:material-icons-*:$m2-version |
Fabryka materiału kompozycyjnego | androidx.compose.material:material-ripple:$m2-version |
Eksperymentalne interfejsy API
Niektóre interfejsy M3 są uważane za eksperymentalne. W takich przypadkach musisz wyrazić zgodę na poziomie funkcji lub pliku, używając adnotacji ExperimentalMaterial3Api
:
import androidx.compose.material3.ExperimentalMaterial3Api
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppComposable() {
// M3 composables
}
Motywy
Zarówno w wersji M2, jak i M3 funkcja kompozycyjna motywu nazywa się MaterialTheme
, ale pakiety importu i parametry różnią się:
M2
import androidx.compose.material.MaterialTheme
MaterialTheme(
colors = AppColors,
typography = AppTypography,
shapes = AppShapes
) {
// M2 content
}
M3
import androidx.compose.material3.MaterialTheme
MaterialTheme(
colorScheme = AppColorScheme,
typography = AppTypography,
shapes = AppShapes
) {
// M3 content
}
Kolor
System kolorów w M3 różni się znacznie od tego w M2. Wzrosła liczba parametrów koloru, mają one różne nazwy i odmienne są mapowane w inny sposób niż komponenty M3. W Compose dotyczy to klasy M2
Colors
, klasy M3
ColorScheme
i powiązanych funkcji:
M2
import androidx.compose.material.lightColors
import androidx.compose.material.darkColors
val AppLightColors = lightColors(
// M2 light Color parameters
)
val AppDarkColors = darkColors(
// M2 dark Color parameters
)
val AppColors = if (darkTheme) {
AppDarkColors
} else {
AppLightColors
}
M3
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
val AppLightColorScheme = lightColorScheme(
// M3 light Color parameters
)
val AppDarkColorScheme = darkColorScheme(
// M3 dark Color parameters
)
val AppColorScheme = if (darkTheme) {
AppDarkColorScheme
} else {
AppLightColorScheme
}
Ze względu na znaczne różnice między systemami kolorów M2 i M3 nie ma odpowiedniego mapowania dla parametrów Color
. Zamiast tego użyj narzędzia Material Theme Builder, aby wygenerować schemat kolorów M3. Użyj kolorów M2 jako podstawowych kolorów w narzędziu, które następnie rozwija się w palety tonalne używane w schemacie kolorów M3. Na początek zalecamy użycie tych mapowań:
M2 | Kreator motywów Material Design |
---|---|
primary |
Główny |
primaryVariant |
Secondary |
secondary |
Tertiary |
surface lub background |
Nie mam zdania |
Możesz skopiować z tego narzędzia wartości szesnastkowych kodów kolorów dla motywów jasnych i ciemnych, a następnie użyć ich do zaimplementowania wystąpienia klasy M3 ColorScheme. Kod Compose może też wyeksportować narzędzie Material Theme Builder.
isLight
W przeciwieństwie do klasy Colors
M2 klasa ColorScheme
M3 nie zawiera parametru isLight
. Ogólnie rzecz biorąc, należy spróbować modelować wszystko, co wymaga tych informacji na poziomie motywu. Na przykład:
M2
import androidx.compose.material.lightColors
import androidx.compose.material.darkColors
import androidx.compose.material.MaterialTheme
@Composable
private fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (darkTheme) darkColors(…) else lightColors(…)
MaterialTheme(
colors = colors,
content = content
)
}
@Composable
fun AppComposable() {
AppTheme {
val cardElevation = if (MaterialTheme.colors.isLight) 0.dp else 4.dp
…
}
}
M3
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.MaterialTheme
val LocalCardElevation = staticCompositionLocalOf { Dp.Unspecified }
@Composable
private fun AppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val cardElevation = if (darkTheme) 4.dp else 0.dp
CompositionLocalProvider(LocalCardElevation provides cardElevation) {
val colorScheme = if (darkTheme) darkColorScheme(…) else lightColorScheme(…)
MaterialTheme(
colorScheme = colorScheme,
content = content
)
}
}
@Composable
fun AppComposable() {
AppTheme {
val cardElevation = LocalCardElevation.current
…
}
}
Więcej informacji znajdziesz w przewodniku na temat niestandardowego projektowania systemów w tworzeniu wiadomości.
Kolory dynamiczne
Nowością w M3 jest dynamiczny kolor. Zamiast kolorów niestandardowych na Androidzie 12 i nowszych modelach ColorScheme
w M3 M3 może używać tych funkcji:
Typografia
System typograficzny w M3 różni się od tego w M2. Liczba parametrów typograficznych jest mniej więcej taka sama, ale mają one różne nazwy i różnie mapowania na komponenty M3. W przypadku tworzenia wiadomości dotyczy to klasy Typography
M2 i klasy M3 Typography
:
M2
import androidx.compose.material.Typography
val AppTypography = Typography(
// M2 TextStyle parameters
)
M3
import androidx.compose.material3.Typography
val AppTypography = Typography(
// M3 TextStyle parameters
)
Na początek zalecamy te mapowania parametrów TextStyle
:
M2 | M3 |
---|---|
h1 |
displayLarge |
h2 |
displayMedium |
h3 |
displaySmall |
Nie dotyczy | headlineLarge |
h4 |
headlineMedium |
h5 |
headlineSmall |
h6 |
titleLarge |
subtitle1 |
titleMedium |
subtitle2 |
titleSmall |
body1 |
bodyLarge |
body2 |
bodyMedium |
caption |
bodySmall |
button |
labelLarge |
Nie dotyczy | labelMedium |
overline |
labelSmall |
Kształt
System kształtów w M3 różni się od tego w M2. Zwiększono liczbę parametrów kształtu, zmieniono ich nazwy i sposób mapowania na komponenty M3. W edytorze dotyczy to klasy M2 Shapes
i klasy M3 Shapes
:
M2
import androidx.compose.material.Shapes
val AppShapes = Shapes(
// M2 Shape parameters
)
M3
import androidx.compose.material3.Shapes
val AppShapes = Shapes(
// M3 Shape parameters
)
Na początek zalecamy użycie tych mapowań parametrów Shape
:
M2 | M3 |
---|---|
Nie dotyczy | extraSmall |
small |
small |
medium |
medium |
large |
large |
Nie dotyczy | extraLarge |
Komponenty i układy
Większość komponentów i schematów z M2 jest dostępna w M3. Brakuje jednak niektórych z nich, a pojawiły się nowe, których nie było w M2. Ponadto niektóre komponenty M3 mają więcej odmian niż ich odpowiedniki w M2. Zasadniczo interfejsy API M3 starają się być jak najbardziej zbliżone do swoich odpowiedników w M2.
Ze względu na zaktualizowane systemy kolorów, typografii i kształtów komponenty M3 są zwykle mapowane inaczej do nowych wartości motywów. Warto sprawdzić katalog z tokenami w kodzie źródłowym Compose Material 3, aby uzyskać informacje o tych mapowaniach.
Chociaż niektóre komponenty wymagają szczególnej uwagi, na początek zalecamy użycie tych map funkcji:
Brakujące interfejsy API:
M2 | M3 |
---|---|
androidx.compose.material.swipeable |
Jeszcze niedostępne |
Zastąpione interfejsy API:
M2 | M3 |
---|---|
androidx.compose.material.BackdropScaffold |
Brak odpowiednika M3, zamiast tego przeprowadź migrację do Scaffold lub BottomSheetScaffold |
androidx.compose.material.BottomDrawer |
Brak odpowiednika M3, zamiast tego przeprowadź migrację do ModalBottomSheet |
Zmiana nazw interfejsów API:
Wszystkie inne interfejsy API:
Najnowsze komponenty i układy M3 znajdziesz w omówieniu interfejsu Compose Material 3 API. Nowe i zaktualizowane interfejsy API znajdziesz na stronie z wersjami API.
Scaffold, paski powiadomień i szuflada nawigacji
Scaffold w M3 różni się od M2. Zarówno w M2, jak i w M3 główny komponent układu ma nazwę Scaffold
, ale pakiety importu i parametry różnią się:
M2
import androidx.compose.material.Scaffold
Scaffold(
// M2 scaffold parameters
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
// M3 scaffold parameters
)
W M2 Scaffold
parametr backgroundColor
ma teraz nazwę containerColor
w M3 Scaffold
:
M2
import androidx.compose.material.Scaffold
Scaffold(
backgroundColor = …,
content = { … }
)
M3
import androidx.compose.material3.Scaffold
Scaffold(
containerColor = …,
content = { … }
)
Klasa M2 ScaffoldState
nie istnieje już w M3, ponieważ zawiera parametr drawerState
, którego nie trzeba już używać. Aby wyświetlać paski informacji w ramach Scaffold
M3, użyj SnackbarHostState
:
M2
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberScaffoldState
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
content = {
…
scope.launch {
scaffoldState.snackbarHostState.showSnackbar(…)
}
}
)
M3
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
Scaffold(
snackbarHost = { SnackbarHost(snackbarHostState) },
content = {
…
scope.launch {
snackbarHostState.showSnackbar(…)
}
}
)
Wszystkie parametry drawer*
z Scaffold
M2 zostały usunięte z Scaffold
M3. Obejmują one takie parametry jak drawerShape
i drawerContent
. Aby wyświetlić panel nawigacji z elementem M3 Scaffold
, użyj kompozytu panelu nawigacji, takiego jak ModalNavigationDrawer
:
M2
import androidx.compose.material.DrawerValue
import
import androidx.compose.material.Scaffold
import androidx.compose.material.rememberDrawerState
import androidx.compose.material.rememberScaffoldState
val scaffoldState = rememberScaffoldState(
drawerState = rememberDrawerState(DrawerValue.Closed)
)
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
drawerContent = { … },
drawerGesturesEnabled = …,
drawerShape = …,
drawerElevation = …,
drawerBackgroundColor = …,
drawerContentColor = …,
drawerScrimColor = …,
content = {
…
scope.launch {
scaffoldState.drawerState.open()
}
}
)
M3
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.rememberDrawerState
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = {
ModalDrawerSheet(
drawerShape = …,
drawerTonalElevation = …,
drawerContainerColor = …,
drawerContentColor = …,
content = { … }
)
},
gesturesEnabled = …,
scrimColor = …,
content = {
Scaffold(
content = {
…
scope.launch {
drawerState.open()
}
}
)
}
)
Górny pasek aplikacji
Paski aplikacji w M3 różnią się od tych w M2. Zarówno w M2, jak i w M3 główny interfejs kompozytowy paska aplikacji u góry ma nazwę TopAppBar
, ale importowane pakiety i parametry różnią się:
M2
import androidx.compose.material.TopAppBar
TopAppBar(…)
M3
import androidx.compose.material3.TopAppBar
TopAppBar(…)
Jeśli wcześniej treści były wyśrodkowane w ramach M2 TopAppBar
, rozważ użycie M3 CenterAlignedTopAppBar
. Warto też zapoznać się z artykułami MediumTopAppBar
i LargeTopAppBar
.
Górne paski aplikacji M3 zawierają nowy parametr scrollBehavior
, który zapewnia różne funkcje podczas przewijania w klasie TopAppBarScrollBehavior
, np. zmianę wysokości. Funkcja ta działa w połączeniu z przewijaniem treści za pomocą Modifer.nestedScroll
. W TopAppBar
M2 było to możliwe dzięki ręcznej zmianie parametru elevation
:
M2
import androidx.compose.material.AppBarDefaults
import androidx.compose.material.Scaffold
import androidx.compose.material.TopAppBar
val state = rememberLazyListState()
val isAtTop by remember {
derivedStateOf {
state.firstVisibleItemIndex == 0 && state.firstVisibleItemScrollOffset == 0
}
}
Scaffold(
topBar = {
TopAppBar(
elevation = if (isAtTop) {
0.dp
} else {
AppBarDefaults.TopAppBarElevation
},
…
)
},
content = {
LazyColumn(state = state) { … }
}
)
M3
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
TopAppBar(
scrollBehavior = scrollBehavior,
…
)
},
content = {
LazyColumn { … }
}
)
Dolny pasek nawigacyjny / pasek nawigacyjny
Pasek dolny w M2 został w M3 przemianowany na pasek nawigacyjny. W wersji M2 dostępne są komponenty BottomNavigation
i BottomNavigationItem
, a w wersji M3 – komponenty NavigationBar
i NavigationBarItem
:
M2
import androidx.compose.material.BottomNavigation
import androidx.compose.material.BottomNavigationItem
BottomNavigation {
BottomNavigationItem(…)
BottomNavigationItem(…)
BottomNavigationItem(…)
}
M3
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
NavigationBar {
NavigationBarItem(…)
NavigationBarItem(…)
NavigationBarItem(…)
}
Przyciski, przyciski ikon i przyciski typu FAB
Przyciski, przyciski ikon i pływające przyciski poleceń (FAB) w M3 różnią się od tych w M2. M3 zawiera wszystkie komponenty kompozytowe przycisku M2:
M2
import androidx.compose.material.Button
import androidx.compose.material.ExtendedFloatingActionButton
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.IconButton
import androidx.compose.material.IconToggleButton
import androidx.compose.material.OutlinedButton
import androidx.compose.material.TextButton
// M2 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M2 icon buttons
IconButton(…)
IconToggleButton(…)
// M2 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)
M3
import androidx.compose.material3.Button
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.IconButton
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.TextButton
// M3 buttons
Button(…)
OutlinedButton(…)
TextButton(…)
// M3 icon buttons
IconButton(…)
IconToggleButton(…)
// M3 FABs
FloatingActionButton(…)
ExtendedFloatingActionButton(…)
M3 zawiera też nowe warianty przycisków. Znajdziesz je w dokumentacji referencyjnej interfejsu Compose Material 3 API.
Przełącz
Przełącznik w M3 różni się od tego w M2. Zarówno w M2, jak i w M3 przełącznik jest kompozytowany jako Switch
, ale pakiety importu różnią się:
M2
import androidx.compose.material.Switch
Switch(…)
M3
import androidx.compose.material3.Switch
Switch(…)
Powierzchnie i wysokość
Systemy powierzchni i wysokości w M3 różnią się od tych w M2. W M3 są 2 rodzaje wysokości:
- Wzniesienie cienia (rzuca cień, tak jak w M2)
- tonalne podniesienie (nakłada kolor, nowość w M3);
W sekcji „Tworzenie” dotyczy to funkcji M2 Surface
i funkcji M3 Surface
:
M2
import androidx.compose.material.Surface
Surface(
elevation = …
) { … }
M3
import androidx.compose.material3.Surface
Surface(
shadowElevation = …,
tonalElevation = …
) { … }
W M2 możesz użyć wartości elevation
Dp
w M2 zarówno dla shadowElevation
, jak i tonalElevation
w M3, w zależności od preferencji UX/UI.
Surface
jest komponentem podstawowym dla większości komponentów, więc komponenty te mogą również udostępniać parametry wysokości, które musisz przenieść w taki sam sposób.
Ustawienie tonacji w M3 zastępuje koncepcję nakładek wysokości w ciemnych motywach M2 . W związku z tym klasy ElevationOverlay
i LocalElevationOverlay
nie istnieją w wersji M3, a LocalAbsoluteElevation
w M2 zostało zmienione na LocalAbsoluteTonalElevation
w M3.
akcentowanie i przejrzystość treści.
Nacisk w M3 jest znacznie inny niż w M2. W M2 nacisk kładziony był na używaniu kolorów z określonymi wartościami alfa, aby odróżniać treści, takie jak tekst i ikony. W M3 można teraz zastosować kilka różnych podejść:
- Użycie w kolorów wraz z ich wariantami z rozszerzonego systemu kolorów M3.
- Używanie różnych grubości czcionek.
W związku z tym elementy ContentAlpha
i LocalContentAlpha
nie występują w pliku M3 i muszą zostać zastąpione.
Na początek zalecane są te mapowania:
M2 | M3 |
---|---|
onSurface w aplikacji ContentAlpha.high |
onSurface ogólnie FontWeight.Medium – FontWeight.Black dla tekstu |
onSurface w aplikacji ContentAlpha.medium |
Ogólnie: onSurfaceVariant , FontWeight.Thin –FontWeight.Normal w przypadku tekstu |
onSurface w aplikacji ContentAlpha.disabled |
onSurface.copy(alpha = 0.38f) |
Oto przykład podkreślenia ikony w wersji M2 i M3:
M2
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Icon(…)
}
M3
import androidx.compose.material3.LocalContentColor
// High emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) {
Icon(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurfaceVariant) {
Icon(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
Icon(…)
}
Oto przykłady wyróżnienia tekstu w M2 i M3:
M2
import androidx.compose.material.ContentAlpha
import androidx.compose.material.LocalContentAlpha
// High emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.high) {
Text(…)
}
// Medium emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) {
Text(…)
}
// Disabled emphasis
CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) {
Text(…)
}
M3
import androidx.compose.material3.LocalContentColor
// High emphasis
Text(
…,
fontWeight = FontWeight.Bold
)
// Medium emphasis
Text(
…,
fontWeight = FontWeight.Normal
)
// Disabled emphasis
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)) {
Text(
…,
fontWeight = FontWeight.Normal
)
}
Tła i kontenery
Tła w M2 są nazywane kontenerami w M3. Ogólnie możesz zastąpić parametry background*
w M2 parametrami container*
w M3, używając tych samych wartości.
Na przykład:
M2
Badge(
backgroundColor = MaterialTheme.colors.primary
) { … }
M3
Badge(
containerColor = MaterialTheme.colorScheme.primary
) { … }
Przydatne linki
Więcej informacji o przechodzeniu z wersji M2 na M3 w Compose znajdziesz w tych dodatkowych materiałach.
Dokumenty
Przykładowe aplikacje
- Przykładowa aplikacja Reply M3
- Przykładowa aplikacja Jetchat – migracja z M2 na M3
- Przykładowa aplikacja Jetnews – migracja z M2 na M3
- Już teraz w aplikacji głównej M3 na Androida :moduł core-designsystem
Filmy
Dokumentacja API i kod źródłowy
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy obsługa JavaScript jest wyłączona
- Material Design 2 w Compose
- Material Design 3 w sekcji Tworzenie wiadomości
- Niestandardowe systemy projektowania w Compose