Material Design 2 in Compose

Jetpack Compose bietet eine Implementierung von Material Design, einem umfassenden Designsystem für digitale Schnittstellen schaffen. Die Material Design-Komponenten wie Schaltflächen, Karten, Schalter usw. werden und basieren auf Material Theming, einer systematischen Möglichkeit, Passen Sie Material Design an, um die Marke Ihres Produkts besser widerzuspiegeln. Ein Material Das Design enthält die Attribute Farbe, Typografie und Form. Wenn Sie diese anpassen, -Attribute werden Ihre Änderungen automatisch in den von Ihnen verwendeten Komponenten um Ihre App zu entwickeln.

Jetpack Compose implementiert diese Konzepte mit der MaterialTheme zusammensetzbar:

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

Konfigurieren Sie die Parameter, die Sie an MaterialTheme übergeben, um das Design Ihrer Anwendung zu gestalten.

Zwei kontrastierende Screenshots. Bei der ersten Option wird der Standard-
MaterialTheme-Stil verwendet,
im zweiten Screenshot
ein geänderter Stil.

Abbildung 1: Der erste Screenshot zeigt eine App, die keine Konfiguration MaterialTheme. Daher wird der Standardstil verwendet. Der zweite Screenshot zeigt Eine App, die Parameter an MaterialTheme übergibt, um den Stil anzupassen.

Farbe

Farben werden in „Compose“ mit der Klasse Color modelliert, einer einfachen der Daten-Holding-Klasse.

val Red = Color(0xffff0000)
val Blue = Color(red = 0f, green = 0f, blue = 1f)

Sie können diese beliebig organisieren (als Konstanten der obersten Ebene, in einem Singleton- oder Inline-Definitionen verwenden, empfehlen wir dringend, Farben in Design ändern und die Farben von dort abrufen. Mit diesem Ansatz können Sie dunkles Design und verschachtelte Designs werden jetzt unterstützt.

Beispiel für die Farbvorlage des Designs

Abbildung 2: Das Farbsystem „Material“.

Mit „Compose“ wird das Colors -Klasse zum Modellieren der Farbsystem für Material. Colors bietet Builder-Funktionen zum Erstellen von Light-Sätzen oder dunkel Farben:

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,
    // ...
)

Nachdem Sie Ihre Colors definiert haben, können Sie sie an ein MaterialTheme übergeben:

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

Designfarben verwenden

Sie können die Colors abrufen, die für die zusammensetzbare Funktion MaterialTheme bereitgestellt wurde: mit MaterialTheme.colors.

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

Oberflächen- und Inhaltsfarbe

Für viele Komponenten wird ein Farb- und ein Farbpaar akzeptiert:

Surface(
    color = MaterialTheme.colors.surface,
    contentColor = contentColorFor(color),
    // ...
) { /* ... */ }

TopAppBar(
    backgroundColor = MaterialTheme.colors.primarySurface,
    contentColor = contentColorFor(backgroundColor),
    // ...
) { /* ... */ }

Damit können Sie nicht nur die Farbe einer zusammensetzbaren Funktion festlegen, sondern auch Standardfarbe für den content und die darin enthaltenen zusammensetzbaren Funktionen Viele Für zusammensetzbare Funktionen wird standardmäßig diese Inhaltsfarbe verwendet. Beispiel: Text basiert auf der Basis Farbe für die Inhaltsfarbe des übergeordneten Elements festgelegt. Icon verwendet diese Farbe, um seine Färbung.

Zwei Beispiele für dasselbe Banner in unterschiedlichen Farben

Abbildung 3: Wenn Sie verschiedene Hintergrundfarben festlegen, erhalten Sie unterschiedliche Text- und Symbolfarben.

Die contentColorFor() den entsprechenden "on"-Wert Farbe für alle Designfarben. Wenn Sie beispielsweise eine Hintergrundfarbe für primary festlegen, am Surface wird mit dieser Funktion onPrimary als Inhalt festgelegt. Farbe. Wenn Sie eine Hintergrundfarbe festlegen, die kein Design ist, sollten Sie auch eine die richtige Farbe für den Inhalt hat. LocalContentColor verwenden um die bevorzugte Inhaltsfarbe für den aktuellen Hintergrund abzurufen. Position in der Hierarchie.

Alphaversion von Inhalten

Oftmals geht es darum, die Wichtigkeit von Inhalten zu variieren. und für eine visuelle Hierarchie. Die Lesbarkeit von Text in Material Design Empfehlungen beraten mit unterschiedlichen Deckkraftgraden vermittelt werden.

Jetpack Compose implementiert dies über LocalContentAlpha. Sie können einen Alpha-Content für eine Hierarchie angeben, indem Sie einen Wert angeben. für diese CompositionLocal. Verschachtelte Daten zusammensetzbaren Funktionen können diesen Wert verwenden, um ihren Inhalt als Alpha zu behandeln. Beispiel: Text und Icon standardmäßig die Kombination aus LocalContentColor verwenden, angepasst an LocalContentAlpha. Material gibt einige Standard-Alphawerte an (high, medium, disabled), die vom ContentAlpha-Objekt modelliert werden.

// 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(
        // ...
    )
}

Weitere Informationen zu CompositionLocal finden Sie unter Daten auf lokaler Ebene mit CompositionLocal-Leitfaden.

Screenshot eines Artikeltitels mit verschiedenen Textebenen
Betonung

Abbildung 4: Verschiedene Betonungsstufen auf Text anwenden, um visuell zu kommunizieren Informationshierarchie gesprochen. Die erste Textzeile ist der Titel. und verwendet daher ContentAlpha.high. Die zweite enthält weniger wichtige Metadaten und verwendet daher ContentAlpha.medium.

Dunkles Design

In Compose können Sie für das helle und das dunkle Design unterschiedliche Colors zur zusammensetzbaren Funktion MaterialTheme:

@Composable
fun MyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    MaterialTheme(
        colors = if (darkTheme) DarkColors else LightColors,
        /*...*/
        content = content
    )
}

In diesem Beispiel ist MaterialTheme in eine eigene zusammensetzbare Funktion eingebunden. , der einen Parameter akzeptiert, der angibt, ob ein dunkles Design verwendet werden soll oder nicht. In In diesem Fall ruft die Funktion den Standardwert für darkTheme ab, indem die Funktion Einstellung für das Gerätedesign.

Mit diesem Code können Sie prüfen, ob die aktuellen Colors hell oder dunkel sind:

val isLightTheme = MaterialTheme.colors.isLight
Icon(
    painterResource(
        id = if (isLightTheme) {
            R.drawable.ic_sun_24
        } else {
            R.drawable.ic_moon_24
        }
    ),
    contentDescription = "Theme"
)

Höhen-Overlays

In Material werden Oberflächen in dunklen Designs mit höheren Elevation Höhen-Overlays, die und hellt deren Hintergrund auf. Je höher die Höhe einer Oberfläche, also die Anhebung angedeutet, desto heller wird die Oberfläche.

Diese Overlays werden automatisch von der zusammensetzbaren Funktion Surface angewendet, wenn sowie für alle anderen zusammensetzbaren Materialien mit einer Oberfläche:

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

Screenshot einer App mit leicht unterschiedlichen Farben für Elemente
bei verschiedenen Höhenunterschieden

Abbildung 5: Für die Karten und die Navigationsleiste am unteren Rand wird die Farbe surface verwendet. als Hintergrund verwenden. Da sich die Kacheln und die Navigation am unteren Rand die über dem Hintergrund liegen, unterscheiden sie sich leicht Farben: Die Kacheln sind heller als der Hintergrund und die untere Navigationsleiste leichter als die Karten.

Für benutzerdefinierte Szenarien ohne Surface verwenden Sie LocalElevationOverlay, ein CompositionLocal mit den ElevationOverlay verwendet von Surface Komponenten:

// 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
)

Um Höhen-Overlays zu deaktivieren, geben Sie null an der gewünschten Stelle in einem zusammensetzbare Hierarchie:

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

Eingeschränkte Farbakzente

Material empfiehlt, begrenzte Farben anzuwenden Akzente für dunkles indem Sie die Farbe surface gegenüber der Farbe primary in in den meisten Fällen. Zusammensetzbare Materialien wie TopAppBar und BottomNavigation implementieren Sie dieses Verhalten standardmäßig.

Abbildung 6: Dunkles Material-Design mit begrenzten Farbakzenten. Obere App-Leiste Die Hauptfarbe wird im hellen Design und die Oberflächenfarbe im dunklen Design verwendet.

Verwenden Sie für benutzerdefinierte Szenarien den primarySurface. Erweiterungseigenschaft:

Surface(
    // Switches between primary in light theme and surface in dark theme
    color = MaterialTheme.colors.primarySurface,
    /*...*/
) { /*...*/ }

Typografie

Material definiert einen Typ System, mit einigen semantisch benannten Stilen.

Beispiel für verschiedene Schriftbilder in verschiedenen Stilen

Abbildung 7: Das Materialtypsystem.

Compose implementiert das Typsystem mit den Klassen Typography, TextStyle und schriftarten. Der Typography-Konstruktor bietet Standardeinstellungen für jeden Stil, sodass Sie alle Stile weglassen können, die Sie nicht anpassen möchten:

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, /*...*/) {
    /*...*/
}

Wenn Sie durchgehend dieselbe Schriftart verwenden möchten, geben Sie defaultFontFamily parameter und lassen Sie fontFamily aller TextStyle-Elemente weg:

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

Textstile verwenden

Auf TextStyles kann über MaterialTheme.typography zugegriffen werden. Rufen Sie die Für TextStyle gilt:

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

Screenshot mit einer Mischung aus verschiedenen Schriftbildern für unterschiedliche Zwecke

Abbildung 8: Nutzen Sie verschiedene Schriftarten und Stile, um Ihre Marke auszudrücken.

Form

Material definiert einen Formsystem können Sie um Formen für große, mittlere und kleine Komponenten zu definieren.

Zeigt eine Vielzahl von Material Design-Formen

Abbildung 9: Das Formsystem „Material“.

Compose implementiert das Shape-System mit dem Shapes-Klasse, mit der geben Sie eine CornerBasedShape für jede Größenkategorie:

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, /*...*/) {
    /*...*/
}

Viele Komponenten verwenden diese Formen standardmäßig. Beispiel: Button, TextField und FloatingActionButton auf „klein“ eingestellt, AlertDialog ist standardmäßig „Medium“ und ModalDrawer. ist standardmäßig groß – siehe Formschema-Referenz für die vollständige Zuordnung.

Formen verwenden

Auf Shapes kann über MaterialTheme.shapes zugegriffen werden. Rufen Sie die Shapes ab mit Code wie diesen aussehen:

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

Screenshot einer App, in der mithilfe von Materialformen der Status eines Elements vermittelt wird

Abbildung 10. Verwenden Sie Formen, um Marke oder Zustand zum Ausdruck zu bringen.

Standardstile

Es gibt kein äquivalentes Konzept in der Funktion zur Erstellung von Standardformate aus Android Views. Sie können eine ähnliche Funktionalität bereitstellen, indem Sie Ihre eigenen zusammensetzbaren Funktionen mit der Funktion „Überlastung“ erstellen, die Material-Komponenten umschließen. Um beispielsweise einen Schaltflächenstil zu erstellen, fassen Sie eine Schaltfläche in Ihrer eigenen zusammensetzbaren Funktion zusammen, legen Sie die zu ändernden Parameter direkt fest und stellen Sie andere als Parameter an die enthaltende zusammensetzbare Funktion zur Verfügung.

@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
    )
}

Design-Overlays

Sie können das Äquivalent von Design-Overlays aus Android Views in Compose durch Verschachtelung MaterialTheme zusammensetzbare Funktionen. Weil In MaterialTheme werden Farben, Typografie und Formen standardmäßig auf den aktuellen Designwert gesetzt. Wenn ein Design nur einen dieser Parameter festlegt, behalten die anderen Parameter ihre Standardwerte.

Wenn Sie auf Ansichten basierende Bildschirme zu „Compose“ migrieren, achten Sie außerdem auf die Verwendung des Attributs android:theme. Vermutlich benötigen Sie eine neue MaterialTheme.

In diesem Beispiel wird auf dem Detailbildschirm PinkTheme für den Großteil des Bildschirms und dann BlueTheme für den zugehörigen Bereich verwendet. Siehe Screenshot und Code unten.

Abbildung 11. Verschachtelte Designs:

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

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

Komponentenstatus

Materialkomponenten, mit denen interagiert werden kann (angeklickt, umgeschaltet usw.), in verschiedenen visuellen Zuständen. Zu den Status gehören „Aktiviert“, „Deaktiviert“, „Gedrückt“ usw.

Zusammensetzbare Elemente haben oft einen enabled-Parameter. Wenn Sie sie auf false festlegen, Interaktion und ändert Eigenschaften wie Farbe und Elevation, um Komponentenstatus.

Abbildung 12. Schaltfläche mit enabled = true (links) und enabled = false (rechts)

In den meisten Fällen können Sie sich auf Standardwerte wie Farbe und Höhe verlassen. Wenn Sie Werte konfigurieren möchten, die in verschiedenen Status verwendet werden, gibt es Klassen und Komfortfunktionen verfügbar. Hier ein Beispiel für die Schaltfläche:

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
    )
) { /* ... */ }

Abbildung 13. Schaltfläche mit enabled = true (links) und enabled = false (rechts) mit angepassten Farb- und Höhenwerten.

Kreise im Wasser

Bei Materialkomponenten wird mit Wellen angezeigt, dass mit ihnen interagiert wird. Wenn Sie MaterialTheme in Ihrer Hierarchie verwenden, wird ein Ripple als StandardIndication in Modifikatoren wie clickable und indication

In den meisten Fällen können Sie auf die Standardeinstellung Ripple zurückgreifen. Falls Sie das Ihres Erscheinungsbilds, können Sie RippleTheme Eigenschaften wie Farbe und Alpha ändern.

Sie können RippleTheme verlängern und die defaultRippleColor und defaultRippleAlpha Dienstprogrammfunktionen. Sie können dann Ihr benutzerdefiniertes Wellenthema in Ihrer Hierarchie mithilfe von 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
    )
}

Alt-Text

Abbildung 14: Schaltflächen mit unterschiedlichen Wellenwerten werden über RippleTheme bereitgestellt.

Weitere Informationen

Weitere Informationen zu Material Theming in Compose findest du hier: zusätzliche Ressourcen.

Codelabs

Videos