Jetpack Compose oferuje implementację Material Design, kompleksowego systemu projektowania do tworzenia interfejsów cyfrowych. Komponenty Material Design (przyciski, karty, przełączniki itp.) są oparte na motywach Material, czyli systematycznym sposobie dostosowywania Material Design do marki produktu. Motyw Material zawiera atrybuty kolor, typografia i kształt. Gdy dostosujesz te atrybuty, zmiany zostaną automatycznie odzwierciedlone w komponentach, których używasz do tworzenia aplikacji.
Jetpack Compose implementuje te koncepcje za pomocą funkcji kompozycyjnej MaterialTheme:
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Skonfiguruj parametry przekazywane do MaterialTheme, aby dostosować wygląd aplikacji.
 
  Kolor
Kolory są modelowane w Compose za pomocą klasy Color, która przechowuje dane.
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
Możesz je uporządkować w dowolny sposób (jako stałe najwyższego poziomu, w ramach singletonu lub zdefiniowane w tekście), ale zdecydowanie zalecamy określanie kolorów w motywie i pobieranie ich stamtąd. Takie podejście umożliwia obsługę ciemnego motywu i zagnieżdżonych motywów.
 
  Biblioteka Compose udostępnia klasę Colors do modelowania systemu kolorów Material. Colors udostępnia funkcje do tworzenia zestawów jasnych lub ciemnych kolorów:
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
Po zdefiniowaniu Colors możesz przekazać je do MaterialTheme:
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Używanie kolorów motywu
Wartość Colors przekazaną do elementu kompozycyjnego MaterialTheme możesz pobrać za pomocą funkcji MaterialTheme.colors.
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
Kolor powierzchni i treści
Wiele komponentów akceptuje parę kolorów i kolorów treści:
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Dzięki temu możesz nie tylko ustawić kolor elementu kompozycyjnego, ale też podać domyślny kolor treści, czyli elementów kompozycyjnych, które zawiera. Wiele funkcji kompozycyjnych domyślnie używa tego koloru treści. Na przykład Text opiera swój kolor na kolorze treści elementu nadrzędnego, a Icon używa tego koloru do ustawienia odcienia.
 
  Metoda contentColorFor() pobiera odpowiedni kolor „włączony” dla dowolnych kolorów motywu. Jeśli na przykład ustawisz kolor tła primary na Surface, ta funkcja ustawi kolor treści onPrimary.
Jeśli ustawisz kolor tła inny niż kolor motywu, musisz też określić odpowiedni kolor treści. Użyj LocalContentColor, aby pobrać preferowany kolor treści
dla bieżącego tła w danym miejscu w hierarchii.
Przezroczystość treści
Często chcesz zmieniać stopień podkreślenia treści, aby przekazać ich znaczenie i zapewnić hierarchię wizualną. Zalecenia dotyczące czytelności tekstu w Material Design sugerują stosowanie różnych poziomów krycia, aby przekazywać różne poziomy ważności.
Jetpack Compose implementuje to za pomocą LocalContentAlpha. Możesz określić wartość alfa treści dla hierarchii, podając wartość dla tego CompositionLocal. Zagnieżdżone funkcje kompozycyjne mogą używać tej wartości do zastosowania efektu alfa do swoich treści. Na przykład Text i Icon domyślnie używają kombinacji LocalContentColor dostosowanej do używania LocalContentAlpha. Materiał określa niektóre standardowe wartości alfa (high, medium, disabled), które są modelowane przez obiekt ContentAlpha.
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Więcej informacji o CompositionLocal znajdziesz w artykule Dane o lokalnym zakresie z użyciem funkcji CompositionLocal.
 
  ContentAlpha.high. Drugi wiersz zawiera mniej istotne metadane, dlatego używa ContentAlpha.medium.Ciemny motyw
W Compose motywy jasny i ciemny wdraża się, podając różne zestawy Colors do funkcji kompozycyjnej MaterialTheme:
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
W tym przykładzie funkcja MaterialTheme jest opakowana w osobną funkcję kompozycyjną, która przyjmuje parametr określający, czy ma być używany ciemny motyw. W tym przypadku funkcja pobiera wartość domyślną dla darkTheme, wysyłając zapytanie do ustawienia motywu urządzenia.
Aby sprawdzić, czy bieżące Colors są jasne czy ciemne, możesz użyć takiego kodu:
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Nakładki wysokości
W Materialu powierzchnie w ciemnych motywach o większej wysokości otrzymują nakładki wysokości, które rozjaśniają ich tło. Im wyższa jest powierzchnia (czyli im bliżej jest domniemanego źródła światła), tym jaśniejsza się staje.
Komponent Surface automatycznie stosuje te nakładki, gdy używasz ciemnych kolorów. Podobnie robi każdy inny komponent Material, który korzysta z powierzchni:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
 
  surface jako tło. Karty i nawigacja u dołu znajdują się na różnych poziomach nad tłem, dlatego mają nieco inne kolory – karty są jaśniejsze niż tło, a nawigacja u dołu jest jaśniejsza niż karty.W przypadku scenariuszy niestandardowych, które nie obejmują Surface, użyj
LocalElevationOverlay, czyli CompositionLocal zawierającego
ElevationOverlay używany przez komponenty Surface:
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Aby wyłączyć nakładki z wysokością, podaj wartość null w wybranym punkcie hierarchii kompozycyjnej:
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Ograniczone akcenty kolorystyczne
W przypadku ciemnych motywów Material zaleca stosowanie ograniczonych akcentów kolorystycznych, preferując w większości przypadków kolor surface zamiast koloru primary. Komponenty Material, takie jak TopAppBar i BottomNavigation, domyślnie implementują to zachowanie.
 
  W przypadku scenariuszy niestandardowych użyj właściwości rozszerzenia primarySurface:
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Typografia
Material definiuje system typów, zachęcając do używania niewielkiej liczby stylów o nazwach semantycznych.
 
  Compose implementuje system typów za pomocą klas Typography, TextStyle i związanych z czcionkami. Konstruktor Typography oferuje wartości domyślne dla każdego stylu, więc możesz pominąć te, których nie chcesz dostosowywać:
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Jeśli chcesz używać tego samego kroju pisma w całym dokumencie, określ parametr
defaultFontFamily i pomijaj parametr fontFamily w elementach
TextStyle:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Używanie stylów tekstu
Dostęp do elementów TextStyle uzyskuje się za pomocą elementu MaterialTheme.typography. Pobierz elementy TextStyle w ten sposób:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
 
  Kształt
Materiał definiuje system kształtów, który umożliwia określanie kształtów dużych, średnich i małych komponentów.
 
  Compose implementuje system kształtów za pomocą klasy Shapes, która umożliwia określenie CornerBasedShape dla każdej kategorii rozmiaru:
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
Wiele komponentów domyślnie używa tych kształtów. Na przykład Button, TextField i FloatingActionButton domyślnie mają rozmiar mały, AlertDialog domyślnie ma rozmiar średni, a ModalDrawer domyślnie ma rozmiar duży. Pełne mapowanie znajdziesz w dokumentacji schematu kształtów.
Używanie kształtów
Dostęp do elementów Shape uzyskuje się za pomocą elementu MaterialTheme.shapes. Pobierz elementy
Shape za pomocą kodu takiego jak ten:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
 
  Style domyślne
W Compose nie ma odpowiednika domyślnych stylów z Androida Views. Podobną funkcjonalność możesz uzyskać, tworząc własne funkcje kompozycyjne overload, które opakowują komponenty Material. Aby na przykład utworzyć styl przycisku, umieść go we własnej funkcji kompozycyjnej, bezpośrednio ustawiając parametry, które chcesz lub musisz zmienić, i udostępniając inne jako parametry funkcji kompozycyjnej zawierającej przycisk.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Nakładki motywu
W Compose możesz uzyskać efekt podobny do nakładek motywu z widoków Androida, zagnieżdżając komponenty MaterialTheme. Ponieważ
MaterialTheme domyślnie ustawia kolory, typografię i kształty na bieżącą wartość motywu, wszystkie inne parametry zachowują swoje wartości domyślne, gdy motyw ustawia tylko jeden z tych parametrów.
Podczas przenoszenia ekranów opartych na widokach do Compose zwróć uwagę na użycie atrybutu android:theme. Prawdopodobnie w tej części drzewa interfejsu Compose potrzebujesz nowego elementu MaterialTheme.
W tym przykładzie ekran szczegółów używa PinkTheme na większości ekranu, a następnie BlueTheme w sekcji powiązanych. Tę koncepcję ilustruje poniższy zrzut ekranu i kod:
 
  
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
Stany komponentu
Komponenty Material, z którymi można wchodzić w interakcje (klikać, przełączać itp.), mogą mieć różne stany wizualne. Możliwe stany to włączony, wyłączony, naciśnięty itp.
Funkcje kompozycyjne często mają parametr enabled. Ustawienie false uniemożliwia interakcję i zmienia właściwości, takie jak kolor i wysokość, aby wizualnie przekazać stan komponentu.
 
  enabled = true (po lewej) i enabled = false (po prawej).W większości przypadków możesz polegać na wartościach domyślnych, takich jak kolor i wysokość. Jeśli musisz skonfigurować wartości używane w różnych stanach, możesz skorzystać z dostępnych klas i funkcji pomocniczych. Przyjrzyj się temu przykładowi przycisku:
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
 
  enabled = true (po lewej) i enabled = false (po prawej) z dostosowanymi wartościami koloru i wysokości.Kręgi na wodzie
Komponenty Material używają efektu fali, aby wskazać, że użytkownik wchodzi z nimi w interakcję. Jeśli w hierarchii używasz znaku MaterialTheme, znak Ripple jest używany jako domyślny Indication w modyfikatorach takich jak clickable i indication.
W większości przypadków możesz użyć domyślnego ustawienia Ripple. Jeśli chcesz skonfigurować ich wygląd, możesz użyć RippleTheme, aby zmienić właściwości, takie jak kolor i wartość alfa.
Możesz rozszerzyć RippleTheme i korzystać z funkcji narzędziowych defaultRippleColor i defaultRippleAlpha. Następnie możesz podać niestandardowy motyw efektu fali w hierarchii za pomocą elementu LocalRippleTheme:
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
 
  RippleTheme.Więcej informacji
Więcej informacji o motywach Material w Compose znajdziesz w tych materiałach.
Codelabs
Filmy
Polecane dla Ciebie
- Uwaga: tekst linku jest wyświetlany, gdy język JavaScript jest wyłączony.
- Niestandardowe systemy projektowania w Compose
- Migracja z Material 2 do Material 3 w Compose
- Ułatwienia dostępu w Compose
