Designs in Compose with Material 3

1. Einführung

In diesem Codelab erfährst du, wie du deine Apps in Jetpack Compose in Material Design 3 erstellst. Außerdem lernen Sie die wichtigsten Bausteine von Farbschema, Typografie und Formen von Material Design 3 kennen, mit denen Sie Ihre Anwendung personalisieren und barrierefrei gestalten können.

Außerdem lernen Sie die Unterstützung dynamischer Designs mit verschiedenen Betonungsebenen kennen.

Lerninhalte

In diesem Codelab lernen Sie:

  • Wichtige Aspekte des Material 3-Themas
  • Material 3-Farbschemata und wie du Designs für deine App generierst
  • Dynamisches und helles/dunkles Design für Ihre App unterstützen
  • Typografie und Formen zum Personalisieren deiner App
  • Material 3-Komponenten und Anpassung des Stils deiner App

Umfang

In diesem Codelab entwickeln Sie eine E-Mail-Client-App namens „Antworten“. Sie beginnen mit einer ungestalteten Anwendung, die das Basisdesign verwendet, und wenden das, was Sie gelernt haben, auf ein Design der Anwendung und die Unterstützung von dunklen Designs an.

d15db3dc75a9d00f.png

Standardstart der App mit dem Basisthema

Sie erstellen Ihr Design mit Farbschema, Typografie und Formen und wenden es dann auf die E-Mail-Liste und die Detailseite Ihrer App an. Außerdem werden der App dynamische Designs unterstützt. Am Ende des Codelabs wirst du sowohl Farb- als auch dynamische Designs für deine App unterstützen.

1357cdbfaaa67721.png

Endpunkt des Codelabs mit hellen und dynamischen Designs.

1357cdbfaaa67721.png

Endpunkt des Design-Codelabs mit dunklen und dynamischen Designs.

Voraussetzungen

2. Einrichtung

In diesem Schritt laden Sie den vollständigen Code der Antwort-App herunter, den Sie in diesem Codelab gestalten werden.

Code abrufen

Den Code für dieses Codelab finden Sie im GitHub-Repository android-compose-codelabs. Führen Sie zum Klonen folgenden Befehl aus:

$ git clone https://github.com/googlecodelabs/android-compose-codelabs

Alternativ können Sie zwei ZIP-Dateien herunterladen:

Beispiel-App ausprobieren

Der Code, den Sie gerade heruntergeladen haben, enthält Code für alle verfügbaren Compose-Codelabs. Öffnen Sie für dieses Codelab das Projekt ThemingCodelab in Android Studio.

Wir empfehlen, mit dem Code im Hauptzweig zu beginnen und das Codelab Schritt für Schritt in Ihrem eigenen Tempo zu befolgen. Sie können beide Versionen jederzeit in Android Studio ausführen, indem Sie den Git-Zweig des Projekts ändern.

Startcode erkunden

Der Hauptcode enthält ein UI-Paket mit den folgenden Hauptpaketen und Dateien, mit denen Sie interagieren werden:

  • MainActivity.kt: Einstiegspunktaktivität, bei der du die Antwort-App startest.
  • com.example.reply.ui.theme: Dieses Paket enthält Designs, Typografie und Farbschemas. Sie werden diesem Paket Material-Design hinzufügen.
  • com.example.reply.ui.components: Enthält die benutzerdefinierten Komponenten der App wie Listenelemente, App-Leisten usw. Sie wenden Designs auf diese Komponenten an.
  • ReplyApp.kt: Dies ist unsere zusammensetzbare Hauptfunktion, in der die UI-Struktur beginnt. Sie wenden in dieser Datei das übergeordnete Thema an.

In diesem Codelab werden ui-Paketdateien behandelt.

3. Material 3-Design

Jetpack Compose bietet eine Implementierung von Material Design, einem umfassenden Designsystem zum Erstellen digitaler Oberflächen. Die Material Design-Komponenten (Schaltflächen, Karten, Schalter usw.) basieren auf Material Theming. Dies ist eine systematische Möglichkeit, Material Design so anzupassen, dass es die Marke Ihres Produkts besser widerspiegelt.

Das Design von Material 3 umfasst die folgenden Subsysteme, mit denen du deiner App Designs hinzufügen kannst: Farbschema, Typografie und Formen. Wenn Sie diese Werte anpassen, werden Ihre Änderungen automatisch in die M3-Komponenten übernommen, mit denen Sie Ihre App erstellen. Sehen wir uns die einzelnen Subsysteme genauer an und implementieren sie in der Beispiel-App.

Subsysteme von Material Design: Farbe, Typografie und Formen.

Material 3-Subsystem aus Farben, Typografie und Formen.

4. Farbschemata

Die Grundlage eines Farbschemas ist ein Satz von fünf Schlüsselfarben, die sich jeweils auf eine Tonpalette mit 13 Tönen beziehen, die von Material 3-Komponenten verwendet werden.

Fünf grundlegende Farben für die Erstellung eines M3-Themas.

Fünf grundlegende Farben zum Erstellen eines M3-Themas.

Jede Akzentfarbe (primär, sekundär und tertiär) wird dann in vier kompatiblen Farben in verschiedenen Farbtönen zur Verfügung gestellt, um sie zu koppeln, Betonung zu definieren und visuell auszudrücken.

Vier Tonfarben der Primär-, Sekundär- und Tertiären Grundfarben.

Vier Tonfarben der Primär-, Sekundär- und Tertiären Grundfarben.

In ähnlicher Weise werden neutrale Farben in vier kompatible Töne unterteilt, die für Oberflächen und Hintergrund verwendet werden. Sie sind auch wichtig, um Textsymbole hervorzuheben, wenn sie auf einer Oberfläche platziert werden.

Vier Tonfarben der neutralen Grundfarben.

Vier Töne von neutralen Grundfarben.

Weitere Informationen zu Farbschema und Farbrollen

Farbschemas generieren

Sie können ein benutzerdefiniertes ColorScheme zwar manuell erstellen, es ist aber oft einfacher, eins anhand der Quellfarben Ihrer Marke zu generieren. Dazu können Sie das Tool Material Theme Builder verwenden und optional den Designcode „Compose“ exportieren.

Sie können eine beliebige Farbe auswählen. Für unseren Anwendungsfall verwenden Sie jedoch die standardmäßige primäre Farbe für Antworten #825500. Klicken Sie links im Bereich Kernfarben auf Primäre Farbe und fügen Sie den Code in der Farbauswahl hinzu.

294f73fc9d2a570e.png

Primären Farbcode in Material Theme Builder hinzufügen

Sobald Sie die Hauptfarbe im Material Theme Builder hinzugefügt haben, sollten Sie das folgende Design und die Option zum Exportieren in der oberen rechten Ecke sehen. Für dieses Codelab exportieren Sie das Design in Jetpack Compose.

Material Theme Builder mit der Option zum Exportieren oben rechts.

Material Theme Builder mit der Option zum Exportieren oben rechts.

Die Hauptfarbe #825500 generiert das folgende Design, das du der App hinzufügst. Material 3 bietet eine breite Palette von Farbrollen, um den Zustand, die Auffälligkeit und Betonung einer Komponente flexibel zum Ausdruck zu bringen.

Helles und dunkles Farbschema aus der Hauptfarbe exportiert.

Das helle und dunkle Farbschema wurde aus der Hauptfarbe exportiert.

The Color.kt generierte Datei enthält die Farben Ihres Designs mit allen Rollen, die sowohl für das helle als auch für das dunkle Design definiert sind.

Color.kt

package com.example.reply.ui.theme
import androidx.compose.ui.graphics.Color

val md_theme_light_primary = Color(0xFF825500)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFFFDDB3)
val md_theme_light_onPrimaryContainer = Color(0xFF291800)
val md_theme_light_secondary = Color(0xFF6F5B40)
val md_theme_light_onSecondary = Color(0xFFFFFFFF)
val md_theme_light_secondaryContainer = Color(0xFFFBDEBC)
val md_theme_light_onSecondaryContainer = Color(0xFF271904)
val md_theme_light_tertiary = Color(0xFF51643F)
val md_theme_light_onTertiary = Color(0xFFFFFFFF)
val md_theme_light_tertiaryContainer = Color(0xFFD4EABB)
val md_theme_light_onTertiaryContainer = Color(0xFF102004)
val md_theme_light_error = Color(0xFFBA1A1A)
val md_theme_light_errorContainer = Color(0xFFFFDAD6)
val md_theme_light_onError = Color(0xFFFFFFFF)
val md_theme_light_onErrorContainer = Color(0xFF410002)
val md_theme_light_background = Color(0xFFFFFBFF)
val md_theme_light_onBackground = Color(0xFF1F1B16)
val md_theme_light_surface = Color(0xFFFFFBFF)
val md_theme_light_onSurface = Color(0xFF1F1B16)
val md_theme_light_surfaceVariant = Color(0xFFF0E0CF)
val md_theme_light_onSurfaceVariant = Color(0xFF4F4539)
val md_theme_light_outline = Color(0xFF817567)
val md_theme_light_inverseOnSurface = Color(0xFFF9EFE7)
val md_theme_light_inverseSurface = Color(0xFF34302A)
val md_theme_light_inversePrimary = Color(0xFFFFB951)
val md_theme_light_shadow = Color(0xFF000000)
val md_theme_light_surfaceTint = Color(0xFF825500)
val md_theme_light_outlineVariant = Color(0xFFD3C4B4)
val md_theme_light_scrim = Color(0xFF000000)

val md_theme_dark_primary = Color(0xFFFFB951)
val md_theme_dark_onPrimary = Color(0xFF452B00)
val md_theme_dark_primaryContainer = Color(0xFF633F00)
val md_theme_dark_onPrimaryContainer = Color(0xFFFFDDB3)
val md_theme_dark_secondary = Color(0xFFDDC2A1)
val md_theme_dark_onSecondary = Color(0xFF3E2D16)
val md_theme_dark_secondaryContainer = Color(0xFF56442A)
val md_theme_dark_onSecondaryContainer = Color(0xFFFBDEBC)
val md_theme_dark_tertiary = Color(0xFFB8CEA1)
val md_theme_dark_onTertiary = Color(0xFF243515)
val md_theme_dark_tertiaryContainer = Color(0xFF3A4C2A)
val md_theme_dark_onTertiaryContainer = Color(0xFFD4EABB)
val md_theme_dark_error = Color(0xFFFFB4AB)
val md_theme_dark_errorContainer = Color(0xFF93000A)
val md_theme_dark_onError = Color(0xFF690005)
val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
val md_theme_dark_background = Color(0xFF1F1B16)
val md_theme_dark_onBackground = Color(0xFFEAE1D9)
val md_theme_dark_surface = Color(0xFF1F1B16)
val md_theme_dark_onSurface = Color(0xFFEAE1D9)
val md_theme_dark_surfaceVariant = Color(0xFF4F4539)
val md_theme_dark_onSurfaceVariant = Color(0xFFD3C4B4)
val md_theme_dark_outline = Color(0xFF9C8F80)
val md_theme_dark_inverseOnSurface = Color(0xFF1F1B16)
val md_theme_dark_inverseSurface = Color(0xFFEAE1D9)
val md_theme_dark_inversePrimary = Color(0xFF825500)
val md_theme_dark_shadow = Color(0xFF000000)
val md_theme_dark_surfaceTint = Color(0xFFFFB951)
val md_theme_dark_outlineVariant = Color(0xFF4F4539)
val md_theme_dark_scrim = Color(0xFF000000)


val seed = Color(0xFF825500)

Die generierte The Theme.kt-Datei enthält eine Konfiguration für helle und dunkle Farbschemas und das App-Design. Außerdem enthält sie die zusammensetzbare Hauptfunktion für das Thema: AppTheme().

Theme.kt

package com.example.reply.ui.theme

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable


private val LightColors = lightColorScheme(
   primary = md_theme_light_primary,
   onPrimary = md_theme_light_onPrimary,
   primaryContainer = md_theme_light_primaryContainer,
   onPrimaryContainer = md_theme_light_onPrimaryContainer,
   secondary = md_theme_light_secondary,
   onSecondary = md_theme_light_onSecondary,
   secondaryContainer = md_theme_light_secondaryContainer,
   onSecondaryContainer = md_theme_light_onSecondaryContainer,
   tertiary = md_theme_light_tertiary,
   onTertiary = md_theme_light_onTertiary,
   tertiaryContainer = md_theme_light_tertiaryContainer,
   onTertiaryContainer = md_theme_light_onTertiaryContainer,
   error = md_theme_light_error,
   errorContainer = md_theme_light_errorContainer,
   onError = md_theme_light_onError,
   onErrorContainer = md_theme_light_onErrorContainer,
   background = md_theme_light_background,
   onBackground = md_theme_light_onBackground,
   surface = md_theme_light_surface,
   onSurface = md_theme_light_onSurface,
   surfaceVariant = md_theme_light_surfaceVariant,
   onSurfaceVariant = md_theme_light_onSurfaceVariant,
   outline = md_theme_light_outline,
   inverseOnSurface = md_theme_light_inverseOnSurface,
   inverseSurface = md_theme_light_inverseSurface,
   inversePrimary = md_theme_light_inversePrimary,
   surfaceTint = md_theme_light_surfaceTint,
   outlineVariant = md_theme_light_outlineVariant,
   scrim = md_theme_light_scrim,
)


private val DarkColors = darkColorScheme(
   primary = md_theme_dark_primary,
   onPrimary = md_theme_dark_onPrimary,
   primaryContainer = md_theme_dark_primaryContainer,
   onPrimaryContainer = md_theme_dark_onPrimaryContainer,
   secondary = md_theme_dark_secondary,
   onSecondary = md_theme_dark_onSecondary,
   secondaryContainer = md_theme_dark_secondaryContainer,
   onSecondaryContainer = md_theme_dark_onSecondaryContainer,
   tertiary = md_theme_dark_tertiary,
   onTertiary = md_theme_dark_onTertiary,
   tertiaryContainer = md_theme_dark_tertiaryContainer,
   onTertiaryContainer = md_theme_dark_onTertiaryContainer,
   error = md_theme_dark_error,
   errorContainer = md_theme_dark_errorContainer,
   onError = md_theme_dark_onError,
   onErrorContainer = md_theme_dark_onErrorContainer,
   background = md_theme_dark_background,
   onBackground = md_theme_dark_onBackground,
   surface = md_theme_dark_surface,
   onSurface = md_theme_dark_onSurface,
   surfaceVariant = md_theme_dark_surfaceVariant,
   onSurfaceVariant = md_theme_dark_onSurfaceVariant,
   outline = md_theme_dark_outline,
   inverseOnSurface = md_theme_dark_inverseOnSurface,
   inverseSurface = md_theme_dark_inverseSurface,
   inversePrimary = md_theme_dark_inversePrimary,
   surfaceTint = md_theme_dark_surfaceTint,
   outlineVariant = md_theme_dark_outlineVariant,
   scrim = md_theme_dark_scrim,
)

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
   val colors = if (!useDarkTheme) {
       LightColors
   } else {
       DarkColors
   }

   MaterialTheme(
       colorScheme = colors,
       content = content
   )
}

Das Hauptelement für die Implementierung von Designs in Jetpack Compose ist die zusammensetzbare Funktion MaterialTheme.

Sie verpacken die zusammensetzbare Funktion MaterialTheme() in der Funktion AppTheme(), die zwei Parameter benötigt:

  • useDarkTheme: Dieser Parameter ist mit der Funktion isSystemInDarkTheme() verknüpft, mit der die Einstellungen für das Systemdesign erfasst und das helle oder dunkle Design angewendet wird. Wenn du für deine App manuell ein helles oder dunkles Design verwenden möchtest, kannst du einen booleschen Wert an useDarkTheme übergeben.
  • content: der Inhalt, auf den das Design angewendet wird.

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
   val colors = if (!useDarkTheme) {
       LightColors
   } else {
       DarkColors
   }

   MaterialTheme(
       colorScheme = colors,
       content = content
   )
}

Wenn Sie jetzt versuchen, die App auszuführen, sollten Sie sehen, dass es genauso aussieht. Auch wenn Sie das neue Farbschema mit neuen Designfarben importiert haben, sehen Sie immer noch die Grundlinien-Designs, da Sie das Design nicht auf die Editor-App angewendet haben.

App mit Basisthema, wenn kein Design angewendet wird.

App mit Grundlinienmotiv, wenn kein Design angewendet wird.

Um das neue Design anzuwenden, fassen Sie in MainActivity.kt die zusammensetzbare Hauptfunktion ReplyApp mit der thematischen Hauptfunktion AppTheme() zusammen.

MainActivity.kt

setContent {
   val uiState by viewModel.uiState.collectAsStateWithLifecycle()

   AppTheme {
       ReplyApp(/*..*/)
   }
}

Sie werden auch die Vorschaufunktionen aktualisieren, um zu sehen, welches Design auf die App-Vorschauen angewendet wird. Schließen Sie die zusammensetzbare Funktion ReplyApp in ReplyAppPreview() mit dem AppTheme ein, um sie auf die Vorschauen anzuwenden.

Sie haben in den Vorschauparametern sowohl das helle als auch das dunkle Systemdesign definiert, sodass Sie beide Vorschauen sehen können.

MainActivity.kt

@Preview(
   uiMode = Configuration.UI_MODE_NIGHT_YES,
   name = "DefaultPreviewDark"
)
@Preview(
   uiMode = Configuration.UI_MODE_NIGHT_NO,
   name = "DefaultPreviewLight"
)
@Composable
fun ReplyAppPreview() {
   AppTheme {
       ReplyApp(
           replyHomeUIState = ReplyHomeUIState(
               emails = LocalEmailsDataProvider.allEmails
           )
       )
   }
}

Wenn Sie die App jetzt ausführen, sollten Sie App-Vorschauen mit den importierten Designfarben anstelle des Basisdesigns sehen.

fddf7b9cc99b1fe3.png be7a661b4553167b.png

App mit Grunddesign (links).

App mit importiertem Farbdesign (rechts)

674cec6cc12db6a0.png

Helle und dunkle App-Vorschauen mit importierten Farbdesigns.

Material 3 unterstützt sowohl helle als auch dunkle Farbschemas. Sie haben die App nur mit dem importierten Design umschlossen. Material 3-Komponenten verwenden Standardfarbrollen.

Sehen wir uns die Farbrollen und ihre Verwendung an, bevor du sie der App hinzufügst.

Farbrollen und Bedienungshilfen

Jede Farbrolle kann je nach Zustand, Auffälligkeit und Betonung der Komponente an verschiedenen Stellen verwendet werden.

1f184a05ea57aa84.png

Farbrollen der Primär-, Sekundär- und Tertiärfarben.

Primär ist die Grundfarbe, die für die Hauptkomponenten wie auffällige Schaltflächen und aktive Status verwendet wird.

Die sekundäre Schlüsselfarbe wird für weniger auffällige Komponenten auf der Benutzeroberfläche verwendet, z. B. Infofelder für Filter.

Die tertiäre Schlüsselfarbe wird verwendet, um kontrastierende Akzente zu setzen, und neutrale Farben für den Hintergrund und die Oberflächen in der App.

Das Farbsystem von Material bietet standardmäßige Tonwerte und -Messungen, die verwendet werden können, um barrierefreie Kontrastverhältnisse zu erreichen. Verwenden Sie den primären Container auf dem Primärcontainer, den primären Container auf dem primären Container und dasselbe für andere Akzent- und neutrale Farben, um dem Nutzer einen barrierefreien Kontrast zu bieten.

Weitere Informationen finden Sie unter Farbrollen und Bedienungshilfen.

Höhen in Ton und Schatten

Material 3 stellt Erhebungen in erster Linie mithilfe von Ton-Overlays dar. Dies ist eine neue Möglichkeit, Container und Oberflächen voneinander zu unterscheiden – bei einer Erhöhung der Höhe in Ton wird ein besserer Ton verwendet – zusätzlich zu Schatten.

Höhen in Tonnenhöhe mit Schatten Die Töne auf Ebene 2, für die die Farbe des Bereichs für die primäre Farbe verwendet wird.

Höhen-Overlays in dunklen Designs wurden in Material Design 3 in Tonfarben-Overlays geändert. Die Overlay-Farbe stammt aus der primären Farbfläche.

Die M3-Oberfläche, die hinter den meisten M3-Komponenten zusammensetzbar ist, unterstützt sowohl Höhen in Ton als auch Schatten:

Surface(
   modifier = modifier,
   tonalElevation = {..}
   shadowElevation = {..}
) {
   Column(content = content)
}

Hinzufügen von Farben zur App

Wenn Sie die App ausführen, werden die exportierten Farben in der App angezeigt, in der die Komponenten die Standardfarben übernehmen. Da wir nun die Farbrollen und die Verwendung kennen, ordnen wir der App die richtigen Farbrollen zu.

be7a661b4553167b.png

App mit Farbdesign und Komponenten, die Standardfarbrollen übernehmen.

Oberflächenfarben

Auf dem Startbildschirm packen Sie zuerst die zusammensetzbare Haupt-App in eine Surface(), um die Basis für die Platzierung der App-Inhalte darüber zu schaffen. Öffnen Sie MainActivity.kt und umschließen Sie die zusammensetzbare ReplyApp()-Datei mit Surface.

Außerdem geben Sie eine Höhe von 5.dp an, um der Oberfläche die Farbe des primären Slots zu verleihen. So entsteht ein Kontrast zum Listenelement und zur Suchleiste darüber. Die Höhe von Tonwert und Schatten für die Oberfläche beträgt standardmäßig 0.dp.

MainActivity.kt

AppTheme {
   Surface(tonalElevation = 5.dp) {
       ReplyApp(
           replyHomeUIState = uiState,
          // other parameters
         )
   }
}

Wenn Sie Ihre Anwendung jetzt ausführen und sowohl die Listen- als auch die Detailseite sehen, sollte die Tonwertoberfläche auf die gesamte App angewendet werden.

be7a661b4553167b.png e70d762495173610.png

App-Hintergrund ohne Oberfläche und Farbton (links).

App-Hintergrund mit angewendeter Oberflächen- und Farbton (rechts)

Farben der App-Leiste

Die benutzerdefinierte Suchleiste oben hat den vom Design vorgegebenen Hintergrund nicht deutlich. Standardmäßig wird die Standardbasisoberfläche ausgewählt. Sie können einen Hintergrund bereitstellen, um eine klare Trennung zu erzielen.

5779fc399d8a8187.png

Benutzerdefinierte Suchleiste ohne Hintergrund (links).

Benutzerdefinierte Suchleiste mit Hintergrund (rechts).

Jetzt bearbeiten Sie ui/components/ReplyAppBars.kt, das die App-Leiste enthält. Du fügst MaterialTheme.colorScheme.background dem zusammensetzbaren Modifier von Row hinzu.

ReplyAppBars.kt

@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(MaterialTheme.colorScheme.background),
       verticalAlignment = Alignment.CenterVertically
   ) {
       // Search bar content
   }
}

Sie sollten jetzt einen deutlichen Abstand zwischen der Tonfläche und der App-Leiste mit Hintergrundfarbe sehen.

b1b374b801dadc06.png

Suchleiste mit Hintergrundfarbe auf der Tonfläche.

Farben der unverankerten Aktionsschaltflächen

70ceac87233fe466.png

Große UAS ohne Themen (links).

Thematisch große UAS mit tertiärer Farbe (rechts).

Auf dem Startbildschirm kannst du das Aussehen der unverankerten Aktionsschaltfläche (UAS) optimieren, sodass sie sich als Call-to-Action-Schaltfläche hervorheben lässt. Um dies zu implementieren, wenden Sie eine tertiäre Akzentfarbe darauf an.

Aktualisiere in der Datei ReplyListContent.kt die containerColor für die UAS auf tertiaryContainer und die Inhaltsfarbe auf onTertiaryContainer, um die Zugänglichkeit und den Farbkontrast beizubehalten.

ReplyListContent.kt

ReplyInboxScreen(/*..*/) {
// Email list content
  LargeFloatingActionButton(
    containerColor = MaterialTheme.colorScheme.tertiaryContainer,
    contentColor = MaterialTheme.colorScheme.onTertiaryContainer
  ){
   /*..*/   
  }
}

Führe die App aus, um dein UAS-Design zu sehen. In diesem Codelab verwenden Sie ein LargeFloatingActionButton.

Kartenfarben

Die E-Mail-Liste auf dem Startbildschirm verwendet eine Kartenkomponente. Standardmäßig ist es eine ausgefüllte Karte, bei der die Farbe der Oberflächenvariante für die Containerfarbe verwendet wird, um für einen deutlichen Unterschied zwischen Oberfläche und Kartenfarbe zu sorgen. Compose bietet auch Implementierungen von ElevatedCard und OutlinedCard.

Einige wichtige Elemente können Sie mit sekundären Farbtönen hervorheben. Sie können ui/components/ReplyEmailListItem.kt ändern, indem Sie die Farbe des Kartencontainers mit CardDefaults.cardColors() für wichtige E-Mails aktualisieren:

ReplyEmailListItem.kt

Card(
   modifier =  modifier
       .padding(horizontal = 16.dp, vertical = 4.dp)
       .semantics { selected = isSelected }
       .clickable { navigateToDetail(email.id) },
   colors = CardDefaults.cardColors(
       containerColor = if (email.isImportant)
           MaterialTheme.colorScheme.secondaryContainer
       else MaterialTheme.colorScheme.surfaceVariant
   )
){
  /*..*/   
}

5818200be0b01583.png 9367d40023db371d.png

Markieren Sie das Listenelement mithilfe der sekundären Containerfarbe auf der Tonfläche.

Farbe des Detaillistenelements

Sie haben jetzt ein Design für Ihren Startbildschirm erstellt. Öffnen Sie die Detailseite, indem Sie auf einen Eintrag in der E-Mail-Liste klicken.

7a9ea7cf3e91e9c7.png 79b3874aeca4cd1.png

Standardmäßige Detailseite ohne themenbezogenes Listenelement (links).

Element in Detailliste mit angewendetem Hintergrunddesign (rechts).

Ihrem Listenelement wurde keine Farbe zugewiesen, daher wird die Standardfarbe für die Oberfläche verwendet. Sie wenden eine Hintergrundfarbe auf das Listenelement an, um eine Abgrenzung zu erreichen, und fügen einen Innenabstand hinzu, um den Abstand um den Hintergrund herum bereitzustellen.

ReplyEmailThreadItem.kt

@Composable
fun ReplyEmailThreadItem(
   email: Email,
   modifier: Modifier = Modifier
) {
   Column(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(MaterialTheme.colorScheme.background)
           .padding(20.dp)
    ) {
      // List item content
    }
}

Sie können sehen, dass Sie durch die Bereitstellung des Hintergrunds eine deutliche Trennung zwischen der Tonfläche und dem Listenelement erreichen.

Sie haben jetzt sowohl Start- als auch Detailseiten mit den richtigen Farbrollen und Verwendungen . Sehen wir uns an, wie du in deiner App dynamische Farben einsetzen kannst, um ein noch stärker personalisiertes und stimmiges Nutzererlebnis zu bieten.

5. Dynamische Farben in der App hinzufügen

Dynamische Farben sind der Hauptteil von Material 3. Ein Algorithmus leitet benutzerdefinierte Farben vom Hintergrund eines Nutzers ab, um ihn auf seine Apps und die System-UI anzuwenden.

Mit dynamischen Designs lassen sich Apps noch besser personalisieren. Es bietet den Nutzern auch eine kohärente und nahtlose Erfahrung mit dem Systemthema.

Dynamische Farben sind ab Android 12 verfügbar. Wenn dynamische Farben verfügbar sind, können Sie ein dynamisches Farbschema mit dynamicDarkColorScheme() oder dynamicLightColorScheme() einrichten. Falls nicht, solltest du auf ein standardmäßiges helles oder dunkles ColorScheme zurückgreifen.

Ersetzen Sie den Code der Funktion AppTheme in der Datei Theme.kt durch den folgenden Code:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean =  isSystemInDarkTheme(),
   content: @Composable () -> Unit
) {
   val context = LocalContext.current
   val colors = when {
       (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) -> {
           if (useDarkTheme) dynamicDarkColorScheme(context)
           else dynamicLightColorScheme(context)
       }
       useDarkTheme -> DarkColors
       else -> LightColors
   }
   
      MaterialTheme(
       colorScheme = colors,
       content = content
     )
}

fecc63b4c6034236.png

Dynamisches Design vom Android 13-Hintergrund.

Wenn Sie die App jetzt ausführen, sollten dynamische Designs mit dem Android 13-Standardhintergrund angewendet werden.

Möglicherweise möchten Sie auch, dass die Statusleiste je nach Farbschema, das für das Design Ihrer App verwendet wird, dynamisch gestaltet wird.

1095e2b2c1ffdc14.png

App ohne Farbe für die Statusleiste (links).

App mit angewandter Farbe der Statusleiste (rechts).

Wenn Sie die Farbe der Statusleiste abhängig von der Hauptfarbe Ihres Designs aktualisieren möchten, fügen Sie die Farbe der Statusleiste nach der Farbschemaauswahl in der zusammensetzbaren Funktion AppTheme hinzu:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean =  isSystemInDarkTheme(),
   content: @Composable () -> Unit
) {
 
 // color scheme selection code

 // Add primary status bar color from chosen color scheme.
 val view = LocalView.current
 if (!view.isInEditMode) {
    SideEffect {
        val window = (view.context as Activity).window
        window.statusBarColor = colors.primary.toArgb()
        WindowCompat
            .getInsetsController(window, view)
            .isAppearanceLightStatusBars = useDarkTheme
    }
 }
   
  MaterialTheme(
    colorScheme = colors,
     content = content
   )
}

Wenn Sie die App ausführen, sollte die Statusleiste das Farbschema in der primären Farbe sehen. Sie können auch ein helles und ein dunkles dynamisches Design ausprobieren, indem Sie das dunkle Design des Systems ändern.

69093b5bce31fd43.png

Dynamisches helles Design (links) und dunkles Design (rechts) angewendet auf Android 13-Standardhintergrund.

Bisher haben Sie Ihrer App Farben hinzugefügt, die das Aussehen der App verbessert haben. Sie können jedoch sehen, dass der gesamte Text in der App die gleiche Größe hat, sodass Sie der App jetzt Typografie hinzufügen können.

6. Typografie

Material Design 3 definiert eine Schriftskala. Die Benennung und Gruppierung wurden vereinfacht: Anzeige, Überschrift, Titel, Text und Label, jeweils mit den Größen Large, Medium und Small.

999a161dcd9b0ec4.png

Schriftskala Material 3.

Typografie definieren

Compose bietet neben den vorhandenen Klassen TextStyle und font-related die M3-Klasse Typography zur Modellierung der Material 3-Typskala.

Der Typografie-Konstruktor bietet Standardeinstellungen für jeden Stil, sodass Sie alle Parameter, die Sie nicht anpassen möchten, weglassen können. Weitere Informationen finden Sie unter Typografiestile und ihre Standardwerte.

Sie verwenden in Ihrer App fünf Typografiestile: headlineSmall, titleLarge, bodyLarge, bodyMedium und labelMedium. Diese Stile decken sowohl den Startbildschirm als auch den Detailbildschirm ab.

Bildschirm, der die typografische Verwendung von Titel, Label und Körperstil zeigt.

Bildschirm, der die typografische Verwendung von Titel, Label und Körperstil zeigt.

Rufen Sie als Nächstes das Paket ui/theme auf und öffnen Sie Type.kt. Fügen Sie den folgenden Code hinzu, um anstelle der Standardwerte eine eigene Implementierung für einige der Textstile bereitzustellen:

Type.kt

val typography = Typography(
   headlineSmall = TextStyle(
       fontWeight = FontWeight.SemiBold,
       fontSize = 24.sp,
       lineHeight = 32.sp,
       letterSpacing = 0.sp
   ),
   titleLarge = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 18.sp,
       lineHeight = 28.sp,
       letterSpacing = 0.sp
   ),
   bodyLarge = TextStyle(
       fontWeight = FontWeight.Normal,
       fontSize = 16.sp,
       lineHeight = 24.sp,
       letterSpacing = 0.15.sp
   ),
   bodyMedium = TextStyle(
       fontWeight = FontWeight.Medium,
       fontSize = 14.sp,
       lineHeight = 20.sp,
       letterSpacing = 0.25.sp
   ),
   labelMedium = TextStyle(
       fontWeight = FontWeight.SemiBold,
       fontSize = 12.sp,
       lineHeight = 16.sp,
       letterSpacing = 0.5.sp
   )
)

Ihre Typografie ist jetzt definiert. Um sie zu Ihrem Design hinzuzufügen, übergeben Sie es an die zusammensetzbare Funktion MaterialTheme() in AppTheme:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
  // dynamic theming content

   MaterialTheme(
       colorScheme = colors,
       typography = typography,
       content = content
   )
}

Mit Typografie arbeiten

Genau wie bei den Farben greifen Sie mit MaterialTheme.typography auf den Typografiestil für das aktuelle Design zu. Dadurch erhalten Sie die Typografieinstanz, mit der die gesamte in Type.kt definierte Typografie verwendet wird.

Text(
   text = "Hello M3 theming",
   style = MaterialTheme.typography.titleLarge
)

Text(
   text = "you are learning typography",
   style = MaterialTheme.typography.bodyMedium
)

Ihr Produkt benötigt wahrscheinlich nicht alle 15 Standardstile der Material Design-Typskala. In diesem Codelab werden fünf Größen ausgewählt, während der Rest weggelassen wird.

Da Sie auf die zusammensetzbaren Funktionen von Text() keine Typografie angewendet haben, wird der gesamte Text standardmäßig auf Typography.bodyLarge zurückgesetzt.

Typografie der Startseitenliste

Wenden Sie als Nächstes die Typografie auf die Funktion ReplyEmailListItem in ui/components/ReplyEmailListItem.kt an, um Titel und Labels zu unterscheiden:

ReplyEmailListItem.kt

Text(
   text = email.sender.firstName,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.createdAt,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.subject,
   style = MaterialTheme.typography.titleLarge,
   modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)

Text(
   text = email.body,
   maxLines = 2,
   style = MaterialTheme.typography.bodyLarge,
   overflow = TextOverflow.Ellipsis
)

90645c0765167bb7.png 6c4af2f412c18bfb.png

Startbildschirm ohne Typografie (links).

Startbildschirm mit Typografie (rechts)

Typografie der Detailliste

In ähnlicher Weise fügen Sie die Typografie im Detailbildschirm hinzu, indem Sie alle zusammensetzbaren Textelemente von ReplyEmailThreadItem in ui/components/ReplyEmailThreadItem.kt aktualisieren:

ReplyEmailThreadItem.kt

Text(
   text = email.sender.firstName,
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = stringResource(id = R.string.twenty_mins_ago),
   style = MaterialTheme.typography.labelMedium
)

Text(
   text = email.subject,
   style = MaterialTheme.typography.bodyMedium,
   modifier = Modifier.padding(top = 12.dp, bottom = 8.dp),
)

Text(
   text = email.body,
   style = MaterialTheme.typography.bodyLarge,
   color = MaterialTheme.colorScheme.onSurfaceVariant
)

543ac09e43d8761.png 3412771e95a45f36.png

Detailbildschirm ohne Typografie (links).

Detailbildschirm mit Typografie (rechts)

Typografie anpassen

Mit der Funktion „Schreiben“ können Sie Ihren Textstil ganz einfach anpassen oder eine eigene Schriftart verwenden. Du kannst TextStyle anpassen, um die Schriftart, die Schriftfamilie, den Buchstabenabstand usw. anzupassen.

Sie ändern den Textstil in der Datei theme/Type.kt. Dies wird für alle Komponenten übernommen, die ihn verwenden.

Aktualisieren Sie fontWeight in SemiBold und lineHeight in 32.sp für titleLarge. Dieser Wert wird für den Betreff im Listeneintrag verwendet. Dadurch wird das Thema betont und es wird eine klare Trennung ermöglicht.

Type.kt

...
titleLarge = TextStyle(
   fontWeight = FontWeight.SemiBold,
   fontSize = 18.sp,
   lineHeight = 32.sp,
   letterSpacing = 0.0.sp
),
...

f8d2212819eb0b61.png

Benutzerdefinierte Typografie auf den Betrefftext anwenden

7. Formen

Materialoberflächen können in verschiedenen Formen dargestellt werden. Erzeugt die direkte Aufmerksamkeit, identifiziert Komponenten, kommuniziert den Zustand und drückt die Marke aus.

Formen definieren

In Compose erhält die Klasse Shapes erweiterte Parameter, um neue M3-Formen zu implementieren. Die M3-Formskala ermöglicht ähnlich wie die Schriftskala eine ausdrucksstarke Reihe von Formen auf der Benutzeroberfläche.

In der Formskala gibt es verschiedene Größen von Formen:

  • Sehr klein
  • Klein
  • Mittel
  • Groß
  • Sehr groß

Standardmäßig verfügt jede Form über einen Standardwert, der überschrieben werden kann. Bei Ihrer App verwenden Sie die mittlere Form, um den Listeneintrag zu ändern, Sie können aber auch andere Formen deklarieren. Erstellen Sie eine neue Datei mit dem Namen Shape.kt im Paket ui/theme und fügen Sie den Code für Formen hinzu:

Shape.kt

package com.example.reply.ui.theme

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp

val shapes = Shapes(
   extraSmall = RoundedCornerShape(4.dp),
   small = RoundedCornerShape(8.dp),
   medium = RoundedCornerShape(16.dp),
   large = RoundedCornerShape(24.dp),
   extraLarge = RoundedCornerShape(32.dp)
)

Nachdem Sie Ihre shapes definiert haben, übergeben Sie sie wie für Farben und Typografie an M3 MaterialTheme:

Theme.kt

@Composable
fun AppTheme(
   useDarkTheme: Boolean = isSystemInDarkTheme(),
   content: @Composable() () -> Unit
) {
  // dynamic theming content

   MaterialTheme(
       colorScheme = colors,
       typography = typography,
       shapes = shapes
       content = content
   )
}

Mit Formen arbeiten

Genau wie Farben und Typografie können Sie Formen mithilfe von MaterialTheme.shape auf Material-Komponenten anwenden. So erhalten Sie die Shape-Instanz, um auf Materialformen zuzugreifen.

Auf viele Material-Komponenten werden bereits Standardformen angewendet. Sie können jedoch über verfügbare Flächen Ihre eigenen Formen bereitstellen und auf Komponenten anwenden.

Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}

Standardformwerte für alle Material 3-Komponenten.Zuordnung von Materialkomponenten mithilfe verschiedener Arten von Formen

Die Zuordnung von Formen für alle Komponenten finden Sie in der Shape-Dokumentation.

Zu „Schreiben“ gehören zwei weitere Formen, die Sie verwenden können: RectangleShape und CircleShape. Bei der rechteckigen Form gibt es keinen Rahmenradius, bei der kreisförmigen Form sind die Kanten vollständig eingekreist.

Sie können auch mit Modifiers Formen auf Ihre Komponenten anwenden, die Formen wie Modifier.clip, Modifier.background und Modifier.border annehmen.

Form der App-Leiste

Der Hintergrund der App-Leiste soll abgerundet werden:

f873392abe535494.png

TopAppBar verwendet eine Row mit einer Hintergrundfarbe. Um den Hintergrund mit abgerundeten Ecken zu erhalten, definieren Sie die Form des Hintergrunds, indem Sie CircleShape an den Hintergrundmodifikator übergeben:

ReplyAppBars.kt

@Composable
fun ReplySearchBar(modifier: Modifier = Modifier) {
   Row(
       modifier = modifier
           .fillMaxWidth()
           .padding(16.dp)
           .background(
               MaterialTheme.colorScheme.background,
               CircleShape
           ),
       verticalAlignment = Alignment.CenterVertically
   ) {
       // Search bar content
   }
}

f873392abe535494.png

Form des Detaillistenelements

Du verwendest auf dem Startbildschirm eine Karte, für die standardmäßig Shape.Medium verwendet wird. Auf unserer Detailseite haben Sie jedoch stattdessen eine Spalte mit Hintergrundfarbe verwendet. Wählen Sie eine mittelgroße Form aus, um eine einheitliche Darstellung der Liste zu erreichen.

3412771e95a45f36.png 80ee881c41a98c2a.png

Spalte mit Detaillistenelement ohne Form auf Listeneintrag (links) und mittlerer Form auf Liste (rechts).

ReplyEmailThreadItem.kt

@Composable
fun ReplyEmailThreadItem(
   email: Email,
   modifier: Modifier = Modifier
) {
   Column(
       modifier = modifier
           .fillMaxWidth()
           .padding(8.dp)
           .background(
               MaterialTheme.colorScheme.background,
               MaterialTheme.shapes.medium
           )
           .padding(16.dp)

   ) {
      // List item content
      
   }
}

Beim Ausführen Ihrer App wird jetzt eine detaillierte Bildschirmliste in Form von medium angezeigt.

8. Betonung

Die Hervorhebung in der Benutzeroberfläche hilft dir, einige Inhalte hervorzuheben, z. B. wenn du den Titel von den Untertiteln unterscheiden möchtest. Bei der Betonung in M3 werden Farbvarianten und ihre Farbkombinationen verwendet. Es gibt zwei Möglichkeiten, Betonung hinzuzufügen:

  1. Verwendung von Oberfläche, Oberflächenvariante und Hintergrund sowie oberflächliche und oberflächliche Farben aus dem erweiterten M3-Farbsystem.

Zum Beispiel kann „Oberfläche“ in Kombination mit „Auf der Oberfläche“ verwendet werden, während „Oberflächenvariante“ in Verbindung mit „Auf Oberflächen“ verwendet werden kann, um verschiedene Betonungen zu erzielen.

Oberflächenvarianten können auch mit Akzentfarben verwendet werden, um weniger Betonung als Akzentfarben zu schaffen, aber dennoch zugänglich zu sein und dem Kontrastverhältnis zu folgen.

Farbrollen für Oberfläche, Hintergrund und Oberflächenvarianten

Farbrollen für Oberfläche, Hintergrund und Oberflächenvarianten.

  1. Unterschiedliche Schriftstärken für Text verwenden Wie Sie im Abschnitt „Typografie“ gesehen haben, können Sie für Ihre Schriftskala benutzerdefinierte Gewichtungen festlegen, um verschiedene Betonungen zu erzielen.

Aktualisieren Sie als Nächstes ReplyEmailListItem.kt, um den Unterschied mithilfe der Oberflächenvariante hervorzuheben. Standardmäßig wird für den Inhalt der Karte je nach Hintergrund die Standardinhaltsfarbe verwendet.

Sie ändern die Farbe des Zeit- und Textkörpertexts in onSurfaceVariant. Dadurch wird die Betonung im Vergleich zu onContainerColors reduziert, das standardmäßig auf zusammensetzbare Betreff- und Titeltexte angewendet wird.

2c9b7f2bd016edb8.png 6850ff391f21e4ba.png

Zeit und Textkörper mit derselben Betonung im Vergleich zu Thema und Titel (links).

Zeit und Körper mit geringerer Betonung im Vergleich zu Thema und Titel (rechts).

ReplyEmailListItem.kt

Text(
   text = email.createdAt,
   style = MaterialTheme.typography.labelMedium,
   color = MaterialTheme.colorScheme.onSurfaceVariant
)

Text(
   text = email.body,
   maxLines = 2,
   style = MaterialTheme.typography.bodyLarge,
   color = MaterialTheme.colorScheme.onSurfaceVariant
   overflow = TextOverflow.Ellipsis
)

Bei der wichtigen E-Mail-Karte mit dem Hintergrund secondaryContainer ist die gesamte Textfarbe standardmäßig die Farbe onSecondaryContainer. Bei den anderen E-Mails ist der Hintergrund surfaceVariant,, sodass der gesamte Text standardmäßig auf onSurfaceVariant gesetzt wird.

9. Glückwunsch

Glückwunsch! Du hast dieses Codelab erfolgreich abgeschlossen. Sie haben Material-Designs mit Compose mit Farben, Typografie und Formen sowie dynamischen Farben implementiert, um Ihre Anwendung zu personalisieren und ein personalisiertes Erlebnis zu bieten.

2d8fcabf15ac5202.png 5a4d31db0185dca6.png ce009e4ce560834d.png

Am Ende der Designergebnisse wurden dynamische Farben und ein Farbdesign angewendet.

Nächste Schritte

Sehen Sie sich auch unsere anderen Codelabs unter Erstellungspfad an:

Weitere Informationen

Beispiel-Apps

Referenzdokumente