Material Design 2 w sekcji Utwórz

W Jetpack Compose dostępna jest implementacja Material Design, czyli kompleksowego systemu projektowania tworzenie interfejsów cyfrowych. komponenty Material Design (przyciski, karty, przełączniki itp.); opiera się na technologii Material Design, która pozwala systematycznie dostosować styl Material Design, aby lepiej odzwierciedlał markę Twojego produktu. Materiał Motyw zawiera atrybuty color, typografia i kształt. Gdy dostosujesz te zmiany są automatycznie odzwierciedlane w używanych przez Ciebie komponentach aby stworzyć aplikację.

Jetpack Compose wdraża te koncepcje za pomocą komponentu MaterialTheme:

MaterialTheme(
    colors = // ...
    typography = // ...
    shapes = // ...
) {
    // app content
}

Skonfiguruj parametry przekazywane do MaterialTheme, aby stworzyć motyw aplikacji.

2 zrzuty ekranu przedstawiające kontrastujące treści. pierwszy korzysta z domyślnego stylu MaterialTheme,
a drugi zrzut ekranu ma zmodyfikowany styl.

Rysunek 1. Pierwszy zrzut ekranu przedstawia aplikację, która nie została skonfigurowana. MaterialTheme, więc jest w nim używany styl domyślny. Drugi zrzut ekranu pokazuje aplikację, która przekazuje parametry do MaterialTheme w celu dostosowania stylizacji.

Kolor

Kolory są modelowane w komponowaniu za pomocą klasy Color, która jest prostą klasą przechowującą 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 (pojedynczy lub zdefiniowany w treści) zdecydowanie zalecamy określenie kolorów w z motywu i pobierania kolorów. Takie podejście sprawia, z łatwością obsługi ciemnego motywu i motywów zagnieżdżonych.

Przykład palety kolorów motywu

Rysunek 2. System kolorów Material

Funkcja tworzenia wiadomości udostępnia Colors do modelowania System kolorów Material Design Colors udostępnia funkcje konstruktora 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 je przekazać do MaterialTheme:

MaterialTheme(
    colors = if (darkTheme) DarkColors else LightColors
) {
    // app content
}

Używanie kolorów motywu

Możesz pobrać Colors przekazane do usługi kompozytowej MaterialTheme, używając MaterialTheme.colors.

Text(
    text = "Hello theming",
    color = MaterialTheme.colors.primary
)

Kolor powierzchni i treści

Wiele komponentów ma parę kolorów do koloru 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 komponenta, ale też określić domyślny kolor treści, czyli komponentów zawartych w danym komponencie. Wiele komponentów używa domyślnie tego koloru treści. Na przykład Text opiera się na jest do koloru treści elementu nadrzędnego, a Icon używa go do określenia jego zabarwienie.

Dwa przykłady tego samego banera w różnych kolorach

Rysunek 3. Ustawienie różnych kolorów tła powoduje zmianę koloru tekstu i ikon.

Metoda contentColorFor()pobiera odpowiedni kolor „włączony” dla dowolnych kolorów motywu. Jeśli na przykład ustawisz kolor tła primary, w Surface, używa tej funkcji do ustawiania onPrimary jako treści koloru. Jeśli ustawisz kolor tła niezwiązany z motywem, musisz też określić odpowiedni kolor treści. Użyj formatu LocalContentColor aby pobrać preferowany kolor treści dla bieżącego tła, na dane miejsce w hierarchii.

Alfa treści

Często chcesz zróżnicować sposób wyróżniania treści, aby przekazać ich znaczenie i utworzyć hierarchię wizualną. Zalecamy stosowanie różnych poziomów przezroczystości, aby przekazywać różne poziomy ważności.

Jetpack Compose implementuje to za pomocą LocalContentAlpha. Możesz określić wersję alfa treści w hierarchii, podając wartość dla: CompositionLocal. Zawarte w kompozycjach komponenty mogą używać tej wartości, aby zastosować do treści przetwarzanie alfa. Na przykład Text i Icon domyślnie używają kombinacji LocalContentColor dostosowanych do użycia 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(
        // ...
    )
}

Aby dowiedzieć się więcej o CompositionLocal, zapoznaj się z lokalnie ograniczonymi danymi w CompositionLocal guide.

Zrzut ekranu z tytułem artykułu pokazujący różne poziomy wyróżnienia tekstu

Rysunek 4. Stosuj różne poziomy uwydatniania tekstu, aby wizualnie przedstawić w hierarchii informacji. Pierwszy wiersz tekstu to tytuł, który zawiera najważniejsze informacje, dlatego używa znaku ContentAlpha.high. Druga linia zawiera mniej ważne metadane, dlatego używa ContentAlpha.medium.

Ciemny motyw

W komponowaniu możesz wdrażać motyw jasny i ciemny, przekazując do komponentu Colors różne zestawy:

@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 ujęta w ramy własnej funkcji składanej, która przyjmuje parametr określający, czy ma być używana ciemna tematyka. W tym przypadku funkcja uzyskuje 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ściowe

W Material Design powierzchnie w ciemnych motywach z wyższymi poziomami mają nakładki wysokości, które rozjaśniają tło. Wyższe wysokość powierzchni (podniesienie jej bliżej) do domniemanego źródła światła), tym jaśniejsza staje się powierzchnia.

Te nakładki są stosowane automatycznie przez funkcję kompozycyjną Surface podczas korzystania z ciemnych kolorów, a w przypadku innych elementów Material Design, w których jest używana powierzchnia:

Surface(
    elevation = 2.dp,
    color = MaterialTheme.colors.surface, // color will be adjusted for elevation
    /*...*/
) { /*...*/ }

Zrzut ekranu aplikacji przedstawiający nieco różne kolory elementów
na różnych poziomach wzniesienia

Rysunek 5. Karty i dolne elementy nawigacyjne mają kolor surface jako tło. Karty i dolne elementy nawigacyjne różnią się od siebie poziomy są nieco inne niż w przypadku tła kolorów – karty są jaśniejsze niż tło, a dolna nawigacja jest lżejsze od kart.

W przypadku scenariuszy niestandardowych, które nie obejmują Surface, użyj LocalElevationOverlayCompositionLocal zawierających ElevationOverlay, które są używane 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 wzniesień, podaj null w wybranym punkcie w polu hierarchia kompozycyjna:

MyTheme {
    CompositionLocalProvider(LocalElevationOverlay provides null) {
        // Content without elevation overlays
    }
}

Ograniczone akcenty kolorystyczne

Material Design zaleca stosowanie ograniczonych akcentów kolory w ciemnych tematach. W większości przypadków zaleca się używanie koloru surface zamiast koloru primary. Materiały kompozycyjne Material Design, takie jak TopAppBar i BottomNavigation zaimplementuj takie działanie domyślnie.

Rysunek 6. Ciemny motyw Material Design z ograniczonymi akcentami kolorystycznymi. Górny pasek aplikacji korzysta z koloru głównego w jasnym motywie, a kolor powierzchni w ciemnym motywie.

W przypadku niestandardowych scenariuszy użyj interfejsu primarySurface właściwość rozszerzenia:

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 semantycznie nazwach.

Przykład kilku różnych krojów czcionek w różnych stylach

Rysunek 7. System typów materiału.

Narzędzie Compose implementuje system typów z klasami Typography, TextStyle i 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ć tej samej czcionki w całości, określ defaultFontFamily parameter i pominij fontFamily wszystkich elementów TextStyle:

val typography = Typography(defaultFontFamily = raleway)
MaterialTheme(typography = typography, /*...*/) {
    /*...*/
}

Korzystanie ze stylów tekstu

Do TextStyle można uzyskać dostęp przez MaterialTheme.typography. Pobierz Podobało się to TextStyle osobom:

Text(
    text = "Subtitle2 styled",
    style = MaterialTheme.typography.subtitle2
)

Zrzut ekranu pokazujący różne kroje pisma do różnych celów

Rysunek 8. Wyraź swoją markę, używając różnych krojów i stylów.

Kształt

Materiał definiuje system kształtów, który umożliwia definiowanie kształtów dużych, średnich i małych komponentów.

Pokazuje różne kształty w stylu Material Design.

Rysunek 9. System kształtów Material Design.

Compose wdraża system kształtów za pomocą klasy Shapes, która umożliwia określenie CornerBasedShape dla każdej kategorii rozmiarów:

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,TextFieldFloatingActionButton mają domyślnie rozmiar mały,AlertDialog – średni, a ModalDrawer – duży. Pełną mapę znajdziesz w odniesienie do schematu kształtów.

Korzystanie z kształtów

Elementy Shape są otwierane przez: MaterialTheme.shapes. Odzyskaj Shape za pomocą podobny do tego:

Surface(
    shape = MaterialTheme.shapes.medium, /*...*/
) {
    /*...*/
}

Zrzut ekranu aplikacji, która używa kształtów Material Design do określania stanu elementu

Rysunek 10. Używaj kształtów do przedstawienia marki lub stanu.

Style domyślne

Nie ma analogicznego pojęcia w funkcji Compose style domyślne w widokach Androida. Możesz zapewnić podobną funkcjonalność, tworząc własne „przeciążone” funkcje kompozycyjne opakowujące komponenty Material. Aby na przykład utworzyć styl przycisku, umieść przycisk we własnej funkcji kompozycyjnej, bezpośrednio ustaw parametry, które chcesz zmienić, i przedstaw inne parametry funkcji kompozycyjnej, która zawiera.

@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

Możesz uzyskać efekt nakładek motywów z Android Views w Compose, zagnieżdżając komponenty MaterialTheme. Ponieważ MaterialTheme domyślnie ustawia kolory, typografię i kształty na bieżącą wartość motywu. Jeśli motyw ustawi tylko jeden z tych parametrów, pozostałe parametry zachowają wartości domyślne.

Podczas migracji ekranów opartych na widoku do usługi Compose uważaj na użycie atrybutu android:theme. Prawdopodobnie potrzebny jest nowy MaterialTheme w tej części drzewa interfejsu tworzenia wiadomości.

W tym przykładzie ekran szczegółów korzysta z PinkTheme na większości ekranu, a potem BlueTheme dla powiązanej sekcji. Poniżej znajdziesz zrzut ekranu i kod.

Rysunek 11. Motywy zagnieżdżone.

@Composable
fun DetailsScreen(/* ... */) {
    PinkTheme {
        // other content
        RelatedSection()
    }
}

@Composable
fun RelatedSection(/* ... */) {
    BlueTheme {
        // content
    }
}

Stany komponentu

Komponenty materiału, z którymi można wchodzić w interakcję (klikać, przełączać itp.), mogą mieć różne stany wizualne. Możliwe stany to włączony, wyłączony, wciśnięty itp.

Elementy składane często mają parametr enabled. Ustawienie wartości false uniemożliwia interakcję i zmienia właściwości, takich jak kolor i wysokość, aby wizualnie przekazać stan komponentu.

Rysunek 12. Przycisk z: enabled = true (po lewej) i enabled = false (po prawej).

W większości przypadków możesz polegać na wartościach domyślnych w przypadku koloru i wysokości. Jeśli chcesz skonfigurować wartości używane w różnych stanach, dostępne są klasy i ułatwienia dostępu. Poniżej znajdziesz przykład 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
    )
) { /* ... */ }

Rysunek 13. Przycisk z: enabled = true (po lewej) i enabled = false (po prawej) z dostosowanymi kolorami i wartościami wysokości.

Kręgi na wodzie

Składniki Material Design używają fal, aby wskazać, że użytkownik wchodzi z nimi w interakcję. Jeśli w hierarchii używasz elementu MaterialTheme, jako domyślny elementIndication w modyfikatorach, takich jak clickable i indication, będzie używany element Ripple.

W większości przypadków możesz polegać na domyślnym Ripple. Konfiguracja ich wyglądu, RippleTheme aby zmienić właściwości, takie jak kolor i alfa.

Możesz rozszerzyć RippleTheme i korzystać z funkcji pomocniczych defaultRippleColordefaultRippleAlpha. Następnie możesz podać niestandardowy motyw fali w hierarchii za pomocą 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
    )
}

tekst_alternatywny

Rysunek 14. Przyciski z różnymi wartościami Echo z RippleTheme.

Więcej informacji

Aby dowiedzieć się więcej o motywie Material Design w usłudze Compose, zapoznaj się z tymi artykułami z dodatkowymi zasobami.

Ćwiczenia z programowania

Filmy