1. Einführung
In diesem Codelab erfahren Sie, wie Sie Ihre Apps in Jetpack Compose mit Material Design 3 gestalten. Außerdem erfahren Sie mehr über die wichtigsten Bausteine von Material Design 3: Farbschemas, Typografie und Formen. Damit können Sie Ihre Anwendung auf personalisierte und barrierefreie Weise gestalten.
Außerdem erfahren Sie mehr über die Unterstützung von dynamischen Designs und verschiedenen Hervorhebungsebenen.
Lerninhalte
In diesem Codelab erfahren Sie Folgendes:
- Wichtige Aspekte der Material 3-Thematisierung
- Material 3-Farbschemas und Designs für Ihre App erstellen
- Dynamische und helle/dunkle Designs für Ihre App unterstützen
- Schriftarten und Formen zum Personalisieren Ihrer App
- Material 3-Komponenten und Anpassung zum Gestalten Ihrer App
Umfang
In diesem Codelab gestalten Sie eine E‑Mail-Client-App namens „Antworten“. Sie beginnen mit einer nicht formatierten Anwendung, die das Baseline-Theme verwendet, und wenden das Gelernte an, um die Anwendung zu gestalten und das dunkle Design zu unterstützen.

Standardmäßiger Startpunkt unserer App mit dem Baseline-Design.
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 fügen Sie der App Unterstützung für dynamische Designs hinzu. Am Ende des Codelabs unterstützt Ihre App sowohl Farb- als auch dynamische Designs.

Endpunkt des Codelabs zum Theming mit hellem Farb-Theming und hellem dynamischen Theming.

Endpunkt des Codelabs zum Theming mit dunklem Farb-Theming und dunklem dynamischen Theming.
Voraussetzungen
- Die neueste Version von Android Studio
- Grundlegende Kenntnisse der Kotlin-Sprache
- Grundlegende Kenntnisse von Jetpack Compose
- Grundkenntnisse in Compose-Layouts wie Row, Column und Modifier
2. Einrichtung
In diesem Schritt laden Sie den vollständigen Code der Reply-App herunter, die Sie in diesem Codelab gestalten.
Code abrufen
Den Code für dieses Codelab finden Sie im GitHub-Repository android-compose-codelabs. Führen Sie zum Klonen Folgendes aus:
$ git clone https://github.com/googlecodelabs/android-compose-codelabs
Alternativ können Sie zwei ZIP-Dateien herunterladen:
Beispiel-App ansehen
Der gerade heruntergeladene Code enthält Code für alle verfügbaren Compose-Codelabs. Öffnen Sie das Projekt ThemingCodelab in Android Studio, um dieses Codelab durchzuarbeiten.
Wir empfehlen, mit dem Code im Hauptzweig zu beginnen und dem Codelab Schritt für Schritt in Ihrem eigenen Tempo zu folgen. Sie können jederzeit eine der beiden Versionen in Android Studio ausführen, indem Sie den Git-Branch des Projekts ändern.
Startcode ansehen
Der Hauptcode enthält ein UI-Paket mit den folgenden Hauptpaketen und Dateien, mit denen Sie interagieren werden:
MainActivity.kt: Einstiegspunkt-Aktivität, über die Sie die Reply-App starten.com.example.reply.ui.theme: Dieses Paket enthält Designs, Typografie und Farbschemas. In diesem Paket fügen Sie Material-Theming hinzu.com.example.reply.ui.components: Enthält die benutzerdefinierten Komponenten der App, z. B. Listenelemente und App-Leisten. Sie wenden Designs auf diese Komponenten an.ReplyApp.kt– Dies ist unsere Hauptfunktion, in der der UI-Baum beginnt. In dieser Datei wenden Sie die Thematisierung der obersten Ebene an.
In diesem Codelab geht es um ui-Paketdateien.
3. Material 3-Theming
Jetpack Compose bietet eine Implementierung von Material Design, einem umfassenden Designsystem zum Erstellen digitaler Benutzeroberflächen. Die Komponenten von Material Design (Schaltflächen, Karten, Schalter usw.) basieren auf Material Theming. Damit lässt sich Material Design systematisch an das Branding Ihres Produkts anpassen.
Das Material 3-Design umfasst die folgenden Subsysteme, um Ihrer App ein Design zu geben: Farbschema, Typografie und Formen. Wenn Sie diese Werte anpassen, werden Ihre Änderungen automatisch in den M3-Komponenten übernommen, die Sie zum Erstellen Ihrer App verwenden. Sehen wir uns die einzelnen Subsysteme an und implementieren wir sie in der Beispiel-App.

Material 3-Subsystem für Farben, Typografie und Formen.
4. Farbschemata
Die Grundlage eines Farbschemas ist der Satz aus fünf Hauptfarben, die jeweils zu einer tonalen Palette mit 13 Tönen gehören, die von Material 3-Komponenten verwendet werden.

Fünf grundlegende Schlüsselfarben zum Erstellen eines M3-Designs.
Jede Akzentfarbe (primär, sekundär und tertiär) wird dann in vier kompatiblen Farben mit unterschiedlichen Tönen für die Kombination, die Definition von Akzenten und die visuelle Darstellung bereitgestellt.

Vier tonale Farben der primären, sekundären und tertiären Akzentfarben.
Auch neutrale Farben sind in vier kompatible Töne unterteilt, die für Oberflächen und Hintergründe verwendet werden. Sie sind auch wichtig, um Textsymbole hervorzuheben, wenn sie auf einer beliebigen Oberfläche platziert werden.

Vier tonale Farben der neutralen Baseline-Farben.
Weitere Informationen zum Farbschema und zu Farbrollen
Farbschemata generieren
Sie können zwar manuell ein benutzerdefiniertes ColorScheme erstellen, aber es ist oft einfacher, eines mit den Quellfarben Ihrer Marke zu generieren. Mit dem Tool Material Theme Builder können Sie das tun und optional Compose-Theming-Code exportieren.
Sie können eine beliebige Farbe auswählen. Für unseren Anwendungsfall verwenden Sie jedoch die primäre Standardfarbe für Antworten #825500. Klicken Sie im linken Bereich Kernfarben auf Primär und fügen Sie den Code in die Farbauswahl ein.

Primärfarbcode im Material Theme Builder hinzufügen
Nachdem Sie die Primärfarbe im Material Theme Builder hinzugefügt haben, sollten Sie oben rechts das folgende Design und die Option zum Exportieren sehen. In diesem Codelab exportieren Sie das Theme in Jetpack Compose.

Material Theme Builder mit der Option zum Exportieren rechts oben.
Aus der Primärfarbe #825500 wird das folgende Design generiert, das Sie der App hinzufügen. Material 3 bietet eine Vielzahl von Farbrollen, mit denen sich der Status, die Hervorhebung und die Betonung einer Komponente flexibel ausdrücken lassen.

Helles und dunkles Farbschema aus der Primärfarbe exportiert:
Die The Color.kt-Datei enthält die Farben Ihres Designs mit allen Rollen, die für helle und dunkle Designfarben 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 Datei The Theme.kt enthält eine Einrichtung für helle und dunkle Farbschemas sowie das App-Design. Sie enthält auch die komponierbare Hauptfunktion für das Theming, 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 Kernelement für die Implementierung von Theming in Jetpack Compose ist die zusammensetzbare Funktion MaterialTheme.
Sie schließen die zusammensetzbare Funktion MaterialTheme() in die Funktion AppTheme() ein, die zwei Parameter verwendet:
useDarkTheme: Dieser Parameter ist an die FunktionisSystemInDarkTheme()gebunden, um die Einstellungen für das Systemdesign zu berücksichtigen und das helle oder dunkle Design anzuwenden. Wenn Sie das helle oder dunkle Design Ihrer App manuell beibehalten möchten, können Sie einen booleschen Wert anuseDarkThemeübergeben.content: Die Inhalte, auf die 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 die App jetzt ausführen, sollte sie genauso aussehen wie zuvor. Obwohl Sie unser neues Farbschema mit neuen Designfarben importiert haben, sehen Sie weiterhin das Basisdesign, da Sie das Design nicht auf die Compose-App angewendet haben.

App mit Standarddesign, wenn kein Design angewendet wird
Um das neue Design anzuwenden, umschließen Sie in MainActivity.kt die Haupt-Composable-Funktion ReplyApp mit der Hauptdesignfunktion AppTheme().
MainActivity.kt
setContent {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
AppTheme {
ReplyApp(/*..*/)
}
}
Außerdem aktualisieren Sie die Vorschaufunktionen, damit das Design auf App-Vorschauen angewendet wird. Schließen Sie die ReplyApp-Composable in ReplyAppPreview() ein und verwenden Sie AppTheme, um das Theming auf die Vorschauen anzuwenden.
Sie haben sowohl das helle als auch das dunkle Systemdesign in den Vorschauparametern definiert. Daher werden beide Vorschauen angezeigt.
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.

App mit dem Standarddesign (links)
App mit importiertem Farbschema (rechts)

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.
Bevor Sie Farben in die App einfügen, sollten Sie sich mit den Farbrollen und der Verwendung von Farben vertraut machen.
Farbrollen und Barrierefreiheit
Jede Farbrolle kann je nach Status, Prominenz und Hervorhebung der Komponente an verschiedenen Stellen verwendet werden.

Farbrollen von Primär-, Sekundär- und Tertiärfarben.
Primär ist die Grundfarbe, die für die Hauptkomponenten wie wichtige Schaltflächen und aktive Status verwendet wird.
Die sekundäre Schlüsselfarbe wird für weniger auffällige Komponenten in der Benutzeroberfläche verwendet, z. B. für Filter-Chips.
Die tertiary-Schlüsselfarbe wird verwendet, um kontrastierende Akzente zu setzen. Neutrale Farben werden für den Hintergrund und die Oberflächen in der App verwendet.
Das Farbsystem von Material bietet standardmäßige Farbtonwerte und Messungen, mit denen sich barrierefreie Kontrastverhältnisse erreichen lassen. Verwende „on-primary“ über „primary“, „on-primary-container“ über „primary-container“ und dasselbe für andere Akzent- und neutrale Farben, um einen barrierefreien Kontrast für den Nutzer zu schaffen.
Weitere Informationen finden Sie unter Farbrollen und Barrierefreiheit.
Ton- und Schattenanhebung
In Material 3 wird die Erhebung hauptsächlich durch tonale Farbüberlagerungen dargestellt. Das ist eine neue Möglichkeit, Container und Oberflächen voneinander zu unterscheiden. Neben Schatten wird auch die tonale Erhebung verwendet. Je höher die tonale Erhebung, desto prominenter der Ton.
Tonale Erhebung auf Ebene 2, die die Farbe aus dem primären Farbfeld übernimmt.
Die Elevation-Overlays in dunklen Designs wurden in Material Design 3 ebenfalls in tonale Farb-Overlays geändert. Die Overlay-Farbe stammt aus dem Primärfarben-Slot.
Die M3-Surface-Composable, die den meisten M3-Komponenten zugrunde liegt, unterstützt sowohl tonale als auch Schatten-Erhebung:
Surface(
modifier = modifier,
tonalElevation = {..}
shadowElevation = {..}
) {
Column(content = content)
}
Farben in Apps hinzufügen
Wenn Sie die App ausführen, sehen Sie die exportierten Farben in der App, wo Komponenten Standardfarben annehmen. Nachdem wir uns mit den Farbrollen und ihrer Verwendung vertraut gemacht haben, können wir die App mit den richtigen Farbrollen gestalten.

App mit Farbschema und Komponenten, die Standardfarbrollen verwenden.
Oberflächenfarben
Auf dem Startbildschirm umschließen Sie zuerst die Haupt-App-Composable mit einem Surface(), um die Grundlage für die Inhalte der App zu schaffen. Öffnen Sie MainActivity.kt und umschließen Sie die zusammensetzbare Funktion ReplyApp() mit Surface.
Außerdem wird eine tonale Erhebung von 5 dp bereitgestellt, um der Oberfläche eine tonale Farbe des primären Slots zu geben.Dies trägt dazu bei, Kontrast zum Listenelement und zur Suchleiste darüber zu schaffen. Standardmäßig sind die tonale und die Schatten-Erhebung für die Oberfläche auf 0 dp festgelegt.
MainActivity.kt
AppTheme {
Surface(tonalElevation = 5.dp) {
ReplyApp(
replyHomeUIState = uiState,
// other parameters
)
}
}
Wenn Sie Ihre Anwendung jetzt ausführen und sowohl die Liste als auch die Detailseite sehen, sollte die tonale Oberfläche auf die gesamte App angewendet werden.

App-Hintergrund ohne Oberflächen- und Tonfarbe (links)
App-Hintergrund mit angewendeter Oberflächen- und Tonfarbe (rechts).
Farben der App-Leiste
Die benutzerdefinierte Suchleiste oben hat keinen transparenten Hintergrund, wie im Design gefordert. Standardmäßig wird auf die Standard-Basisoberfläche zurückgegriffen. Sie können einen Hintergrund angeben, um eine klare Trennung zu schaffen.

Benutzerdefinierte Suchleiste ohne Hintergrund (links).
Benutzerdefinierte Suchleiste mit Hintergrund (rechts).
Sie bearbeiten jetzt ui/components/ReplyAppBars.kt, die die App-Leiste enthält. Sie fügen MaterialTheme.colorScheme.background dem Modifier von Row Composable 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 eine klare Trennung zwischen der tonalen Oberfläche und der App-Leiste mit Hintergrundfarbe sehen.

Suchleiste mit Hintergrundfarbe auf einer tonalen Oberfläche.
Farben des unverankerten Aktionsbuttons

Großer schwebender Aktionsschaltfläche ohne angewendetes Design (links)
Großer thematischer schwebender Aktionsschaltfläche mit tertiärer Farbe (rechts)
Auf dem Startbildschirm können Sie das Erscheinungsbild des Floating-Action-Buttons (FAB) so anpassen, dass er als Call-to-Action-Button hervorsticht. Dazu weisen Sie dem Element eine tertiäre Akzentfarbe zu.
Aktualisieren Sie in der Datei ReplyListContent.kt die containerColor für die schwebende Aktionsschaltfläche auf die Farbe tertiaryContainer und die Inhaltsfarbe auf onTertiaryContainer, um die Barrierefreiheit und den Farbkontrast beizubehalten.
ReplyListContent.kt
ReplyInboxScreen(/*..*/) {
// Email list content
LargeFloatingActionButton(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
){
/*..*/
}
}
Führen Sie die App aus, um das FAB mit dem neuen Design zu sehen. In diesem Codelab verwenden Sie eine LargeFloatingActionButton.
Kartenfarben
Die E‑Mail-Liste auf dem Startbildschirm verwendet eine Kartenkomponente. Standardmäßig ist es eine gefüllte Karte, für die die Oberflächenvariantenfarbe für die Containerfarbe verwendet wird, um eine klare Trennung zwischen Oberflächen- und Kartenfarbe zu ermöglichen. Compose bietet auch Implementierungen von ElevatedCard und OutlinedCard.
Sie können einige wichtige Elemente weiter hervorheben, indem Sie sekundäre Farbtöne angeben. Sie ändern ui/components/ReplyEmailListItem.kt, 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
)
){
/*..*/
}

Listenelement mit der sekundären Containerfarbe auf einer tonalen Oberfläche hervorheben:
Farbe des Detaillistenelements
Sie haben jetzt ein Design für Ihren Startbildschirm ausgewählt. Klicken Sie auf eines der Elemente in der E‑Mail-Liste, um die Detailseite aufzurufen.

Standardmäßige Detailseite ohne thematisiertes Listenelement (links)
Detail-Listenelement mit angewendetem Hintergrunddesign (rechts)
Auf Ihr Listenelement wurde keine Farbe angewendet. Daher wird die standardmäßige tonale Oberflächenfarbe verwendet. Sie wenden die Hintergrundfarbe auf das Listenelement an, um es vom Rest der Anzeige abzuheben, und fügen einen Innenabstand hinzu, um den Hintergrund zu umgeben.
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
}
}
Wie Sie sehen, wird durch die Bereitstellung eines Hintergrunds eine klare Trennung zwischen der tonalen Oberfläche und dem Listenelement erreicht.
Sie haben jetzt sowohl Start- als auch Detailseiten mit korrekten Farbrollen und korrekter Verwendung . Sehen wir uns an, wie Ihre App dynamische Farben nutzen kann, um ein noch persönlicheres und einheitlicheres Nutzererlebnis zu bieten.
5. Dynamische Farben in Apps implementieren
Dynamische Farben sind ein wichtiger Bestandteil von Material 3. Dabei leitet ein Algorithmus benutzerdefinierte Farben aus dem Hintergrundbild eines Nutzers ab, die auf seine Apps und die System-UI angewendet werden.
Durch dynamische Designs werden Ihre Apps personalisierter. Außerdem wird Nutzern so eine einheitliche und nahtlose Nutzung mit dem Systemdesign ermöglicht.
Die dynamische Farbgebung ist ab Android 12 verfügbar. Wenn dynamische Farben verfügbar sind, können Sie mit dynamicDarkColorScheme() oder dynamicLightColorScheme() ein dynamisches Farbschema einrichten. Andernfalls sollten Sie auf eine Standard-ColorScheme im hellen oder dunklen Design 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
)
}

Dynamisches Design, das vom Hintergrundbild in Android 13 abgeleitet wurde.
Wenn Sie die App jetzt ausführen, sollte das dynamische Design mit dem Standardhintergrund von Android 13 angewendet werden.
Möglicherweise soll die Statusleiste auch dynamisch gestaltet werden, je nachdem, welches Farbschema für das Design Ihrer App verwendet wird.

App ohne angewendete Statusleistenfarbe (links).
App mit angewendeter Statusleistenfarbe (rechts).
Wenn Sie die Farbe der Statusleiste entsprechend der primären Farbe Ihres Designs aktualisieren möchten, fügen Sie die Farbe der Statusleiste nach der Auswahl des Farbschemas im AppTheme-Composable 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 die Hauptfarbe Ihres Designs annehmen. Sie können auch sowohl das helle als auch das dunkle dynamische Design ausprobieren, indem Sie das dunkle Design des Systems ändern.

Dynamisches helles (links) und dunkles (rechts) Design mit dem Standardhintergrund von Android 13.
Bisher haben Sie Farben auf Ihre App angewendet, um das Aussehen der App zu verbessern. Sie sehen jedoch, dass der gesamte Text in der App dieselbe Größe hat. Sie können der App jetzt Typografie hinzufügen.
6. Typografie
Material Design 3 definiert eine Typografie-Skala. Die Benennung und Gruppierung wurden vereinfacht: Es gibt jetzt die Kategorien „Display“, „Überschrift“, „Titel“, „Textkörper“ und „Label“ mit jeweils den Größen „groß“, „mittel“ und „klein“.

Material 3-Typoskala
Typografie definieren
Compose bietet die M3-Klasse Typography sowie die vorhandenen Klassen TextStyle und font-related, um die Material 3-Typografie zu modellieren.
Der Typography-Konstruktor bietet Standardwerte für jeden Stil, sodass Sie alle Parameter weglassen können, die Sie nicht anpassen möchten. Weitere Informationen finden Sie unter Typografiestile und ihre Standardwerte.
In Ihrer App verwenden Sie fünf Typografiestile: headlineSmall, titleLarge, bodyLarge, bodyMedium und labelMedium. Diese Stile werden sowohl auf dem Startbildschirm als auch auf dem Detailbildschirm angewendet.

Auf dem Bildschirm wird die Verwendung der Typografie für Titel, Label und Textkörper dargestellt.
Rufen Sie als Nächstes das ui/theme-Paket auf und öffnen Sie Type.kt. Fügen Sie den folgenden Code hinzu, um für einige der Textformatierungen eine eigene Implementierung anstelle von Standardwerten zu verwenden:
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. Wenn Sie es Ihrem Design hinzufügen möchten, übergeben Sie es an die MaterialTheme()-Composable-Funktion 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 Farben greifen Sie mit MaterialTheme.typography auf den Typografiestil für das aktuelle Design zu. Dadurch erhalten Sie die Typografie-Instanz, mit der Sie die gesamte definierte Typografie in Type.kt verwenden können.
Text(
text = "Hello M3 theming",
style = MaterialTheme.typography.titleLarge
)
Text(
text = "you are learning typography",
style = MaterialTheme.typography.bodyMedium
)
Für Ihr Produkt sind wahrscheinlich nicht alle 15 Standardstile aus der Material Design-Typografie-Skala erforderlich. In diesem Codelab werden fünf Größen ausgewählt, die restlichen werden weggelassen.
Da Sie keine Typografie auf die Text(-Composables angewendet haben, wird standardmäßig Typography.bodyLarge für alle Texte verwendet.
Typografie der Liste auf der Startseite
Wenden Sie als Nächstes die Typografie auf die Funktion ReplyEmailListItem in ui/components/ReplyEmailListItem.kt an, um zwischen Titeln 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
)

Startbildschirm ohne angewendete Typografie (links)
Startbildschirm mit angewendeter Typografie (rechts)
Typografie der Detailliste
Ebenso fügen Sie die Typografie auf dem Detailbildschirm hinzu, indem Sie alle Text-Composables 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
)

Detailbildschirm ohne angewendete Typografie (links)
Detailbildschirm mit angewendeter Typografie (rechts)
Typografie anpassen
Mit Compose können Sie den Textstil ganz einfach anpassen oder eine benutzerdefinierte Schriftart verwenden. Sie können TextStyle ändern, um Schriftart, Schriftfamilie, Buchstabenabstand usw. anzupassen.
Sie ändern den Textstil in der Datei theme/Type.kt. Die Änderung wird auf alle Komponenten angewendet, in denen der Stil verwendet wird.
Aktualisieren Sie fontWeight auf SemiBold und lineHeight auf 32.sp für titleLarge, das für das Betreff des Listenelements verwendet wird. So wird das Motiv stärker in den Vordergrund gerückt und es entstehen klare Trennungen.
Type.kt
...
titleLarge = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
lineHeight = 32.sp,
letterSpacing = 0.0.sp
),
...

Benutzerdefinierte Typografie auf Betrefftext anwenden
7. Formen
Materialoberflächen können in verschiedenen Formen dargestellt werden. Formen lenken die Aufmerksamkeit, identifizieren Komponenten, kommunizieren den Status und drücken die Marke aus.
Formen definieren
Compose bietet die Klasse Shapes mit erweiterten Parametern zur Implementierung neuer M3-Formen. Die M3-Formskala ähnelt der Typoskala und ermöglicht eine große Bandbreite an Formen in der Benutzeroberfläche.
Die Formskala umfasst verschiedene Größen von Formen:
- Sehr klein
- Klein
- Mittel
- Groß
- Sehr groß
Standardmäßig hat jede Form einen Standardwert, der überschrieben werden kann. Für Ihre App verwenden Sie die Form „medium“, um das Listenelement zu ändern. Sie können aber auch andere Formen deklarieren. Erstellen Sie im Paket ui/theme eine neue Datei mit dem Namen Shape.kt 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 shapes definiert haben, übergeben Sie es an MaterialTheme M3, wie Sie es für Farben und Typografie getan haben:
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 Farbe und Typografie können Sie Formen auf Material-Komponenten anwenden. Dazu verwenden Sie MaterialTheme.shape, wodurch Sie über die Shape-Instanz auf Material-Formen zugreifen können.
Viele Material-Komponenten haben bereits Standardformen, aber Sie können über verfügbare Slots eigene Formen für Komponenten bereitstellen und anwenden.
Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}
*Zuordnung von Materialkomponenten mit verschiedenen Formen.*
Die Zuordnung von Formen für alle Komponenten finden Sie in der Dokumentation zu Formen.
Es gibt zwei weitere Formen, die Sie verwenden können: RectangleShape und CircleShape. Sie sind Teil von Compose. Das Rechteck hat keinen Rahmenradius, der Kreis hat vollständig abgerundete Ecken.
Sie können Formen auch auf Ihre Komponenten anwenden, indem Sie Modifiers verwenden, die Formen annehmen, z. B. Modifier.clip, Modifier.background und Modifier.border.
Form der App-Leiste
Wir möchten, dass die App-Leiste einen Hintergrund mit abgerundeten Ecken hat:

Für TopAppBar wird ein Row mit einer Hintergrundfarbe verwendet. Um einen 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
}
}

Form des Detail-Listenelements
Auf dem Startbildschirm verwenden Sie eine Karte, für die standardmäßig Shape.Medium verwendet wird. Auf der Detailseite haben Sie jedoch stattdessen eine Spalte mit Hintergrundfarbe verwendet. Wenn Sie möchten, dass die Liste einheitlich aussieht, wenden Sie eine mittlere Form darauf an.

Spalte mit Detail-Listenelement ohne Form auf Listenelement (links) und mit mittelgroßer 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
}
}
Wenn Sie Ihre App jetzt ausführen, wird ein detailliertes Bildschirmlistenelement in Form von medium angezeigt.
8. Schwerpunkt
Durch die Hervorhebung in der Benutzeroberfläche können Sie bestimmte Inhalte hervorheben, z. B. wenn Sie den Titel von Untertiteln unterscheiden möchten. In M3 wird durch Farbvariationen und Kombinationen mit der Primärfarbe eine Betonung erzielt. Es gibt zwei Möglichkeiten, Text zu betonen:
- Verwenden Sie die Farben „surface“, „surface-variant“ und „background“ zusammen mit den Farben „on-surface“ und „on-surface-variant“ aus dem erweiterten M3-Farbsystem.
Beispielsweise kann „surface“ mit „on-surface-variant“ und „surface-variant“ mit „on-surface“ verwendet werden, um unterschiedliche Akzentuierungen zu erzielen.
Oberflächenvarianten können auch mit Akzentfarben verwendet werden, um weniger Akzentuierung als bei On-Accent-Farben zu erzielen, aber dennoch zugänglich zu sein und das Kontrastverhältnis einzuhalten.

Farbrollen für Oberfläche, Hintergrund und Oberflächenvariante.
- Verwendung unterschiedlicher Schriftstärken für Text Wie Sie im Abschnitt zur Typografie gesehen haben, können Sie Ihrer Typografie-Skala benutzerdefinierte Schriftstärken zuweisen, um unterschiedliche Akzente zu setzen.
Aktualisieren Sie als Nächstes ReplyEmailListItem.kt, um mit der Oberflächenvariante einen Unterschied in der Hervorhebung zu erzielen. Standardmäßig wird die Standardinhaltsfarbe für den Inhalt der Karte verwendet, die vom Hintergrund abhängt.
Sie aktualisieren die Farbe der Composables für den Zeit- und den Textkörper auf onSurfaceVariant. Dadurch wird die Hervorhebung im Vergleich zu onContainerColors reduziert, das standardmäßig auf Composables für Betreff- und Titeltext angewendet wird.

Uhrzeit und Textkörper mit derselben Hervorhebung wie Betreff und Titel (links).
Zeit und Textkörper mit geringerer Gewichtung im Vergleich zu Betreff 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 Karte für wichtige E‑Mails mit dem Hintergrund secondaryContainer ist standardmäßig die Textfarbe onSecondaryContainer festgelegt. Bei den anderen E‑Mails ist der Hintergrund surfaceVariant,, sodass der gesamte Text standardmäßig die Farbe onSurfaceVariant hat.
9. Glückwunsch
Glückwunsch! Sie haben dieses Codelab erfolgreich abgeschlossen. Sie haben Material-Theming mit Compose implementiert und dabei Farben, Typografie und Formen sowie dynamische Farben verwendet, um Ihre Anwendung zu gestalten und eine personalisierte Nutzererfahrung zu bieten.

Ende der Theming-Ergebnisse mit dynamischen Farben und angewendetem Farbschema.
Nächste Schritte
Weitere Codelabs zum Compose-Lernpfad:
- Grundlagen für das Erstellen von Prompts
- Compose-Layouts
- Zustand in Compose
- Compose für bestehende Apps
Weitere Informationen
- Leitfaden zum Theming in Compose
- Material Theming für Compose
Beispiel-Apps
- Beispiel-App für Antworten mit vollständigem Material 3-Theming
- JetChat mit dynamischer Gestaltung