Jetpack Compose oferuje implementację Material You i Material 3 Expressive, czyli kolejną wersję Material Design. M3 Expressive to rozszerzenie Material Design 3, które obejmuje oparte na badaniach aktualizacje motywów, komponentów, ruchu, typografii i innych elementów. Wszystkie te zmiany mają pomóc Ci w tworzeniu atrakcyjnych i pożądanych produktów, które użytkownicy pokochają. Obsługuje też funkcje personalizacji Material You, takie jak dynamiczny kolor. M3 Expressive uzupełnia styl wizualny i interfejs systemu Android 16.
Poniżej pokazujemy implementację Material Design 3 na przykładzie przykładowej aplikacji Reply. Przykładowa aplikacja Reply jest w całości oparta na Material Design 3.
Zależność
Aby zacząć używać Material 3 w aplikacji Compose, dodaj zależność Compose Material 3 do plików build.gradle:
implementation "androidx.compose.material3:material3:$material3_version"
Po dodaniu zależności możesz zacząć dodawać do aplikacji systemy projektowania Material Design, w tym kolory, typografię i kształty.
Eksperymentalne interfejsy API
Niektóre interfejsy API 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 @Composable fun AppComposable() { // M3 composables }
Material Theming
Motyw M3 zawiera te podsystemy: schemat kolorów, typografię i kształty. Gdy dostosujesz te wartości, zmiany zostaną automatycznie odzwierciedlone w komponentach M3, których używasz do tworzenia aplikacji.
Jetpack Compose implementuje te koncepcje za pomocą funkcji kompozycyjnej M3 MaterialTheme:
MaterialTheme( colorScheme = /* ... typography = /* ... shapes = /* ... ) { // M3 app content }
Aby nadać motyw treściom aplikacji, zdefiniuj schemat kolorów, typografię i kształty charakterystyczne dla aplikacji.
Schemat kolorów
Podstawą schematu kolorów jest zestaw 5 głównych kolorów. Każdy z tych kolorów odnosi się do palety tonalnej składającej się z 13 odcieni, które są używane przez komponenty Material 3. Na przykład tak wygląda schemat kolorów dla jasnego motywu w aplikacji Reply:
Dowiedz się więcej o schemacie kolorów i rolach kolorów.
Generowanie schematów kolorów
Chociaż możesz utworzyć niestandardowy ColorScheme ręcznie, często łatwiej jest wygenerować go przy użyciu kolorów źródłowych Twojej marki. Możesz to zrobić za pomocą narzędzia Material Theme Builder i opcjonalnie wyeksportować kod motywu Compose. Generowane są te pliki:
Color.ktzawiera kolory motywu ze wszystkimi rolami zdefiniowanymi zarówno dla jasnego, jak i ciemnego motywu.
val md_theme_light_primary = Color(0xFF476810) val md_theme_light_onPrimary = Color(0xFFFFFFFF) val md_theme_light_primaryContainer = Color(0xFFC7F089) // .. // .. val md_theme_dark_primary = Color(0xFFACD370) val md_theme_dark_onPrimary = Color(0xFF213600) val md_theme_dark_primaryContainer = Color(0xFF324F00) // .. // ..
Theme.ktzawiera konfigurację jasnych i ciemnych schematów kolorów oraz motywu aplikacji.
private val LightColorScheme = lightColorScheme( primary = md_theme_light_primary, onPrimary = md_theme_light_onPrimary, primaryContainer = md_theme_light_primaryContainer, // .. ) private val DarkColorScheme = darkColorScheme( primary = md_theme_dark_primary, onPrimary = md_theme_dark_onPrimary, primaryContainer = md_theme_dark_primaryContainer, // .. ) @Composable fun ReplyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { val colorScheme = if (!darkTheme) { LightColorScheme } else { DarkColorScheme } MaterialTheme( colorScheme = colorScheme, content = content ) }
Aby obsługiwać jasne i ciemne motywy, użyj isSystemInDarkTheme(). Na podstawie ustawienia systemowego określ, którego schematu kolorów chcesz używać: jasnego czy ciemnego.
Dynamiczne schematy kolorów
Dynamiczny kolor to kluczowy element Material You, w którym algorytm pobiera spersonalizowane kolory z tapety użytkownika i stosuje je w aplikacjach oraz interfejsie systemu. Ta paleta kolorów jest używana jako punkt wyjścia do generowania jasnych i ciemnych schematów kolorów.
Kolor dynamiczny jest dostępny na urządzeniach z Androidem 12 lub nowszym. Jeśli dynamiczny kolor jest dostępny, możesz skonfigurować dynamiczny ColorScheme. Jeśli nie, użyj niestandardowego jasnego lub ciemnego motywu ColorScheme.
ColorScheme udostępnia funkcje kreatora do tworzenia dynamicznego jasnego lub ciemnego schematu kolorów:
// Dynamic color is available on Android 12+ val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S val colors = when { dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current) dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current) darkTheme -> DarkColorScheme else -> LightColorScheme }
Użycie koloru
Dostęp do kolorów Material Theming w aplikacji możesz uzyskać za pomocą:
MaterialTheme.colorScheme
Text( text = "Hello theming", color = MaterialTheme.colorScheme.primary )
Każda rola koloru może być używana w różnych miejscach w zależności od stanu, widoczności i wyróżnienia komponentu.
- Kolor podstawowy to kolor bazowy, który jest używany w przypadku głównych komponentów, takich jak widoczne przyciski, stany aktywne i odcień podniesionych powierzchni.
- Kolor drugorzędny jest używany w mniej widocznych komponentach interfejsu, takich jak elementy filtra, i zwiększa możliwości wyrażania kolorów.
- Trzeciorzędny kolor klucza służy do określania ról kontrastujących akcentów, które mogą być używane do równoważenia kolorów podstawowych i drugorzędnych lub do zwrócenia większej uwagi na dany element.
W projekcie przykładowej aplikacji Reply użyto koloru on-primary-container na kolorze primary-container, aby wyróżnić wybrany element.
Card( colors = CardDefaults.cardColors( containerColor = if (isSelected) MaterialTheme.colorScheme.primaryContainer else MaterialTheme.colorScheme.surfaceVariant ) ) { Text( text = "Dinner club", style = MaterialTheme.typography.bodyLarge, color = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface, ) }
W panelu nawigacji aplikacji Reply widać, jak kolory kontenerów drugorzędnych i trzeciorzędnych są używane w kontraście, aby tworzyć akcenty i wyróżnienia.
Typografia
Material Design 3 definiuje skalę typograficzną, w tym style tekstu, które zostały dostosowane z Material Design 2. Nazewnictwo i grupowanie zostały uproszczone do: wyświetlania, nagłówka, tytułu, treści i etykiety, z których każdy ma duży, średni i mały rozmiar.
| M3 | Domyślny rozmiar czcionki/wysokość wiersza |
displayLarge |
Roboto 57/64 |
displayMedium |
Roboto 45/52 |
displaySmall |
Roboto 36/44 |
headlineLarge |
Roboto 32/40 |
headlineMedium |
Roboto 28/36 |
headlineSmall |
Roboto 24/32 |
titleLarge |
New- Roboto Medium 22/28 |
titleMedium |
Roboto Medium 16/24 |
titleSmall |
Roboto Medium 14/20 |
bodyLarge |
Roboto 16/24 |
bodyMedium |
Roboto 14/20 |
bodySmall |
Roboto 12/16 |
labelLarge |
Roboto Medium 14/20 |
labelMedium |
Roboto Medium 12/16 |
labelSmall |
New Roboto Medium, 11/16 |
Definiowanie typografii
Compose udostępnia klasę M3 Typography oraz istniejące klasy TextStyle i związane z czcionkami, aby modelować skalę typów Material 3. Konstruktor Typography oferuje domyślne wartości dla każdego stylu, więc możesz pominąć parametry, których nie chcesz dostosowywać:
val replyTypography = Typography( titleLarge = TextStyle( fontWeight = FontWeight.SemiBold, fontSize = 22.sp, lineHeight = 28.sp, letterSpacing = 0.sp ), titleMedium = TextStyle( fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp ), // .. ) // ..
Twój produkt prawdopodobnie nie będzie potrzebować wszystkich 15 domyślnych stylów ze skali typograficznej Material Design. W tym przykładzie wybrano 5 rozmiarów, a pozostałe pominięto.
Możesz dostosować typografię, zmieniając domyślne wartości właściwości TextStyle i związanych z czcionką, takich jak fontFamily i letterSpacing.
bodyLarge = TextStyle( fontWeight = FontWeight.Normal, fontFamily = FontFamily.SansSerif, fontStyle = FontStyle.Italic, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp, baselineShift = BaselineShift.Subscript ),
Po zdefiniowaniu Typography przekaż go do MaterialTheme M3:
MaterialTheme( typography = replyTypography, ) { // M3 app Content }
Używanie stylów tekstu
Typografię dostarczoną do funkcji kompozycyjnej MaterialTheme M3 możesz pobrać za pomocą MaterialTheme.typography:
Text( text = "Hello M3 theming", style = MaterialTheme.typography.titleLarge ) Text( text = "you are learning typography", style = MaterialTheme.typography.bodyMedium )
Więcej informacji o wytycznych Material Design dotyczących stosowania typografii znajdziesz w dokumentacji.
Kształty
Powierzchnie Material Design mogą mieć różne kształty. Kształty kierują uwagę, identyfikują komponenty, komunikują stan i wyrażają markę.
Skala kształtu określa styl rogów kontenera, oferując zakres zaokrąglenia od kwadratu do pełnego koła.
Definiowanie kształtów
Compose udostępnia klasę M3 Shapes z rozszerzonymi parametrami, aby obsługiwać nowe kształty M3. Skala kształtów M3 jest bardziej zbliżona do skali typograficznej, co umożliwia stosowanie w interfejsie szerokiej gamy kształtów.
Kształty są dostępne w różnych rozmiarach:
- Bardzo mały
- Mały
- średni,
- Duży
- Bardzo duże
Domyślnie każdy kształt ma wartość domyślną, ale możesz ją zastąpić:
val replyShapes = Shapes( extraSmall = RoundedCornerShape(4.dp), small = RoundedCornerShape(8.dp), medium = RoundedCornerShape(12.dp), large = RoundedCornerShape(16.dp), extraLarge = RoundedCornerShape(24.dp) )
Po zdefiniowaniu Shapes możesz przekazać go do MaterialTheme M3:
MaterialTheme( shapes = replyShapes, ) { // M3 app Content }
Używanie kształtów
Możesz dostosować skalę kształtu dla wszystkich komponentów w MaterialTheme lub dla poszczególnych komponentów.
Zastosuj średni i duży kształt z wartościami domyślnymi:
Card(shape = MaterialTheme.shapes.medium) { /* card content */ } FloatingActionButton( shape = MaterialTheme.shapes.large, onClick = { } ) { /* fab content */ }
W Compose dostępne są jeszcze 2 inne kształty: RectangleShape i CircleShape. Kształt prostokąta nie ma promienia obramowania, a kształt koła ma w pełni zaokrąglone krawędzie:
Card(shape = RectangleShape) { /* card content */ } Card(shape = CircleShape) { /* card content */ }
Poniższe przykłady pokazują niektóre komponenty z zastosowanymi domyślnymi wartościami kształtu:
Więcej informacji o wytycznych dotyczących Material Design znajdziesz w artykule o stosowaniu kształtów.
Wyróżnienie
W M3 wyróżnienie jest realizowane za pomocą odmian kolorów i ich kombinacji. W M3 możesz wyróżnić elementy interfejsu na 2 sposoby:
- Używanie kolorów powierzchni, wariantu powierzchni i tła wraz z kolorami na powierzchni i wariantami na powierzchni z rozszerzonego systemu kolorów M3. Na przykład kolor powierzchni można używać z kolorem na powierzchni, a kolor powierzchni (wariant) z kolorem na powierzchni, aby uzyskać różne poziomy wyróżnienia.
- używanie różnych grubości czcionki w tekście; Wcześniej pokazaliśmy, że możesz podać niestandardowe grubości dla naszej skali typograficznej, aby uzyskać różne akcenty.
bodyLarge = TextStyle( fontWeight = FontWeight.Bold ), bodyMedium = TextStyle( fontWeight = FontWeight.Normal )
Elevation
W Material 3 wysokość jest przedstawiana głównie za pomocą tonalnych nakładek kolorystycznych. To nowy sposób na odróżnienie kontenerów i powierzchni od siebie – zwiększenie tonalnego uniesienia powoduje użycie bardziej wyrazistego tonu – oprócz cieni.
Nakładki wysokości w ciemnych motywach zostały również zmienione na nakładki kolorów tonalnych w Material 3. Kolor nakładki pochodzi z miejsca na kolor podstawowy.
Surface w M3 – element kompozycyjny, który stanowi podstawę większości komponentów M3 – obsługuje zarówno podniesienie tonalne, jak i podniesienie cienia:
Surface( modifier = Modifier, tonalElevation = /*... shadowElevation = /*... ) { Column(content = content) }
Komponenty Material Design
Material Design zawiera bogaty zestaw komponentów Material (takich jak przyciski, elementy, karty czy pasek nawigacyjny), które są już zgodne z Material Theming i pomagają tworzyć piękne aplikacje Material Design. Możesz od razu zacząć używać komponentów z domyślnymi właściwościami.
Button(onClick = { /*..*/ }) { Text(text = "My Button") }
M3 udostępnia wiele wersji tych samych komponentów, które mogą być używane w różnych rolach w zależności od tego, na co chcesz zwrócić uwagę.
- Rozszerzony pływający przycisk polecenia (FAB) dla działania o najwyższym priorytecie:
ExtendedFloatingActionButton( onClick = { /*..*/ }, modifier = Modifier ) { Icon( imageVector = Icons.Default.Edit, contentDescription = stringResource(id = R.string.edit), ) Text( text = stringResource(id = R.string.add_entry), ) }
- Wypełniony przycisk do działania o wysokim kontraście:
Button(onClick = { /*..*/ }) { Text(text = stringResource(id = R.string.view_entry)) }
- Przycisk tekstowy do działania o niskim priorytecie:
TextButton(onClick = { /*..*/ }) { Text(text = stringResource(id = R.string.replated_articles)) }
Możesz dowiedzieć się więcej o przyciskach i innych komponentach Material Design. Material 3 udostępnia szeroką gamę zestawów komponentów, takich jak przyciski, paski aplikacji i komponenty nawigacyjne, które zostały zaprojektowane specjalnie pod kątem różnych przypadków użycia i rozmiarów ekranu.
Komponenty nawigacyjne
Material udostępnia też kilka komponentów nawigacyjnych, które pomagają wdrożyć nawigację w zależności od różnych rozmiarów i stanów ekranu.
NavigationBar jest używany w przypadku urządzeń kompaktowych, gdy chcesz kierować reklamy na maksymalnie 5 miejsc docelowych:
NavigationBar(modifier = Modifier.fillMaxWidth()) { Destinations.entries.forEach { replyDestination -> NavigationBarItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { } ) } }
NavigationRail jest używany w przypadku małych i średnich tabletów lub telefonów w trybie poziomym. Zapewnia użytkownikom ergonomię i poprawia wrażenia z korzystania z tych urządzeń.
NavigationRail( modifier = Modifier.fillMaxHeight(), ) { Destinations.entries.forEach { replyDestination -> NavigationRailItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { } ) } }
BottomNavigationBar (po lewej) i NavigationRail (po prawej)Odpowiedz, używając obu tych elementów w domyślnym motywie, aby zapewnić użytkownikom atrakcyjne wrażenia na urządzeniach o różnych rozmiarach.
NavigationDrawer jest używany na tabletach średniej i dużej wielkości, na których jest wystarczająco dużo miejsca na wyświetlanie szczegółów. Możesz używać właściwości PermanentNavigationDrawer lub ModalNavigationDrawer razem z właściwością NavigationRail.
PermanentNavigationDrawer(modifier = Modifier.fillMaxHeight(), drawerContent = { Destinations.entries.forEach { replyDestination -> NavigationRailItem( selected = selectedDestination == replyDestination, onClick = { }, icon = { }, label = { } ) } }) { }
Opcje nawigacji zwiększają wygodę użytkowników, ergonomię i dostępność. Więcej informacji o komponentach nawigacyjnych Material znajdziesz w ćwiczeniu z programowania dotyczącym tworzenia układów adaptacyjnych.
Dostosowywanie motywu komponentu
M3 zachęca do personalizacji i elastyczności. Wszystkie komponenty mają zastosowane domyślne kolory, ale udostępniają elastyczne interfejsy API, które w razie potrzeby umożliwiają dostosowanie kolorów.
Większość komponentów, takich jak karty i przyciski, udostępnia domyślny obiekt, który ujawnia interfejsy kolorów i wysokości. Można je modyfikować, aby dostosować komponent:
val customCardColors = CardDefaults.cardColors( contentColor = MaterialTheme.colorScheme.primary, containerColor = MaterialTheme.colorScheme.primaryContainer, disabledContentColor = MaterialTheme.colorScheme.surface, disabledContainerColor = MaterialTheme.colorScheme.onSurface, ) val customCardElevation = CardDefaults.cardElevation( defaultElevation = 8.dp, pressedElevation = 2.dp, focusedElevation = 4.dp ) Card( colors = customCardColors, elevation = customCardElevation ) { // m3 card content }
Możesz dowiedzieć się więcej o dostosowywaniu Material 3.
interfejs systemu
Niektóre aspekty Material You pochodzą z nowego stylu wizualnego i interfejsu systemu na Androidzie 12 i nowszych. Dwa główne obszary, w których wprowadzono zmiany, to efekt fali i przewijanie poza krawędź. Wdrożenie tych zmian nie wymaga żadnych dodatkowych działań.
Marszczenie
Efekt fali wykorzystuje teraz subtelne błyski, które rozświetlają powierzchnie po naciśnięciu. Compose Material Ripple używa platformy RippleDrawable na Androidzie, więc efekt fali z błyskami jest dostępny na Androidzie 12 i nowszych we wszystkich komponentach Material.
Overscroll
Przewijanie poza krawędź wykorzystuje teraz efekt rozciągania na krawędzi przewijanych kontenerów.
Rozciąganie przy przewijaniu poza zakres jest domyślnie włączone w komponentach kontenera przewijania, takich jak LazyColumn, LazyRow i LazyVerticalGrid, w Compose Foundation w wersji 1.1.0 i nowszych, niezależnie od poziomu interfejsu API.
Ułatwienia dostępu
Standardy ułatwień dostępu wbudowane w komponenty Material Design mają na celu zapewnienie podstaw do projektowania produktów z myślą o integracji społecznej. Zrozumienie ułatwień dostępu w usłudze może zwiększyć jej użyteczność dla wszystkich użytkowników, w tym osób niedowidzących, niewidomych, niedosłyszących, z zaburzeniami funkcji poznawczych, z niepełnosprawnością ruchową lub z niepełnosprawnością sytuacyjną (np. ze złamaną ręką).
Ułatwienia dostępu dotyczące kolorów
Dynamiczne kolory zostały zaprojektowane tak, aby spełniać standardy ułatwień dostępu dotyczące kontrastu kolorów. System palet tonalnych ma kluczowe znaczenie dla zapewnienia domyślnej dostępności każdego schematu kolorów.
System kolorów Material zapewnia standardowe wartości i pomiary odcieni, które można wykorzystać do uzyskania odpowiednich współczynników kontrastu.
Wszystkie komponenty Material i dynamiczne motywy korzystają już z powyższych ról kolorów z zestawu palet tonalnych, które zostały wybrane pod kątem spełniania wymagań dotyczących ułatwień dostępu. Jeśli jednak dostosowujesz komponenty, pamiętaj, aby używać odpowiednich ról kolorów i unikać niedopasowania.
Używaj koloru on-primary na kolorze primary i on-primary-container na primary-container. To samo dotyczy innych kolorów akcentujących i neutralnych, aby zapewnić użytkownikowi odpowiedni kontrast.
Użycie kontenera trzeciorzędnego na kontenerze podstawowym powoduje, że przycisk ma słaby kontrast:
// ✅ Button with sufficient contrast ratio Button( onClick = { }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.primary, contentColor = MaterialTheme.colorScheme.onPrimary ) ) { } // ❌ Button with poor contrast ratio Button( onClick = { }, colors = ButtonDefaults.buttonColors( containerColor = MaterialTheme.colorScheme.tertiaryContainer, contentColor = MaterialTheme.colorScheme.primaryContainer ) ) { }
Ułatwienia dostępu dotyczące typografii
Skala typów M3 aktualizuje statyczną skalę i wartości typów, aby oferować uproszczoną, ale dynamiczną strukturę kategorii rozmiarów, które można skalować na różnych urządzeniach.
Na przykład w Material 3 do małego wyświetlacza można przypisać różne wartości w zależności od kontekstu urządzenia, np. telefonu lub tabletu.
Duże ekrany
Material zawiera wskazówki dotyczące układów adaptacyjnych i urządzeń składanych, które pomagają zwiększyć dostępność aplikacji i poprawić ergonomię korzystania z dużych urządzeń.
Material oferuje różne rodzaje nawigacji, które pomogą Ci zapewnić użytkownikom lepsze wrażenia na urządzeniach z dużym ekranem.
Możesz dowiedzieć się więcej o wskazówkach dotyczących jakości aplikacji na urządzenia z dużym ekranem i zapoznać się z naszym przykładem aplikacji Reply, aby zobaczyć, jak wygląda projektowanie adaptacyjne i dostępne.
Więcej informacji
Więcej informacji o Material Theming w Compose znajdziesz w tych materiałach:
Przykładowe aplikacje
Dokumenty
Dokumentacja API i kod źródłowy
Filmy
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Migracja z Material 2 do Material 3 w Compose
- Material Design 2 w Compose
- Niestandardowe systemy projektowania w Compose