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 wird die Unterstützung von dynamischen Designs zusammen mit verschiedenen Gewichtungsstufen behandelt.
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 Anpassen des Stils 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 dunkle Designs zu unterstützen.

Standardmäßiger Startpunkt unserer App mit dem Baseline-Theme.
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
- Grundkenntnisse in 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: Einstiegsaktivität, über die Sie die Reply-App starten.com.example.reply.ui.theme: Dieses Paket enthält Designs, Typografie und Farbschemas. Sie fügen diesem Paket 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 Haupt-Composable-Funktion, in der der UI-Baum beginnt. In dieser Datei wenden Sie das Theming 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 den 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 Grundfarben auf Primär und fügen Sie den Code in die Farbauswahl ein.

Primärfarbcode in 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 Design in Jetpack Compose.

Material Theme Builder mit der Option zum Exportieren oben rechts.
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 generierte 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 Thema 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 Baseline-Design, 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 ReplyApp mit der Haupt-Designfunktion 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 zusammensetzbare Funktion ReplyApp 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)

Vorschau der App im hellen und dunklen Modus mit importierten Farbdesigns.
Material 3 unterstützt sowohl helle als auch dunkle Farbschemas. Sie haben die App nur mit dem importierten Design umschlossen. Für Material 3-Komponenten werden Standardfarbrollen verwendet.
Bevor Sie Farben in die App einfügen, sollten Sie sich mit den Farbrollen und der Verwendung von Farben vertraut machen.
Farbrollen und Bedienungshilfen
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 wichtige Komponenten der Benutzeroberfläche verwendet, z. B. für Filter-Chips.
Die primäre Schlüsselfarbe tertiary wird verwendet, um kontrastreiche 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 zugängliche Kontrastverhältnisse erreicht werden können. Verwenden Sie „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 genutzt, wobei ein stärkerer Ton verwendet wird.
Tonale Steigerung auf Ebene 2, bei der die Farbe aus dem primären Farbfeld übernommen wird.
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ären Farbfeld.
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 Farbdesign 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 geben Sie eine tonale Erhöhung von 5 dp an, um der Oberfläche eine tonale Farbe des primären Slots zu geben.So wird ein Kontrast zum Listenelement und zur Suchleiste darüber geschaffen. Standardmäßig ist die tonale und Schatten-Erhebung für die Oberfläche 0 dp.
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 Standardbasisoberflä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, das 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
}
}
Die tonale Oberfläche und die App-Leiste mit Hintergrundfarbe sollten jetzt deutlich voneinander getrennt sein.

Suchleiste mit Hintergrundfarbe auf einer tonalen Oberfläche.
Farben der unverankerten Aktionsschaltfläche

Großer schwebender Aktionsschaltfläche ohne angewendetes Theming (links)
Großer FAB mit Design und 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 Schaltfläche „Aktion“ 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 den schwebenden Aktionsschaltfläche 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 durch sekundäre Farbtöne weiter hervorheben. 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 abzugrenzen, 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 Hintergrundfarbe 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 hinzufügen
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 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
)
}

Dynamisches Design, das vom Hintergrundbild in Android 13 abgeleitet wird.
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 Systemdesign ä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
In Material Design 3 wird eine Typografie-Skala definiert. 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-Typografie
Typografie definieren
Compose bietet die M3-Klasse Typography sowie die vorhandenen Klassen TextStyle und font-related, um die Material 3-Typoskala 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 gelten sowohl für den Startbildschirm als auch für den Detailbildschirm.

Bildschirm mit der typografischen Verwendung von Titel-, Label- und Textformat.
Gehen Sie als Nächstes zum ui/theme-Paket 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. So 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 zu SemiBold und lineHeight zu 32.sp für titleLarge, das für den Betreff im Listenelement verwendet wird. So wird das Motiv stärker in den Vordergrund gerückt und es gibt 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 Typskala und ermöglicht eine große Auswahl 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 mittlere Form, 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 nun Ihre shapes definiert haben, übergeben Sie sie an die M3-MaterialTheme, wie Sie es bereits 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 die Shape-Instanz erhalten, um auf Material-Formen zuzugreifen.
Viele Material-Komponenten haben bereits Standardschaltflächen, 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 */}
Materialkomponenten mit verschiedenen Formen zuordnen:
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 auch Formen 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 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
}
}

Form des Detaillisteneintrags
Auf dem Startbildschirm verwenden Sie eine Karte, für die standardmäßig Shape.Medium verwendet wird. Auf der Detailseite haben Sie jedoch eine Spalte mit Hintergrundfarbe verwendet. Wenn Sie möchten, dass die Liste einheitlich aussieht, weisen Sie ihr eine mittlere Form zu.

Spalte mit Listenelementdetails 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 von anderen abheben, z. B. den Titel von Untertiteln. 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 Gewichtung als bei Akzentfarben zu erzielen, aber dennoch zugänglich zu sein und das Kontrastverhältnis einzuhalten.

Farbrollen für Oberfläche, Hintergrund und Oberflächenvariante.
- Verwenden Sie unterschiedliche 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 für den Inhalt der Karte die Standardfarbe für Inhalte verwendet, die vom Hintergrund abhängt.
Sie aktualisieren die Farbe der zusammensetzbaren Elemente für Zeit- und 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 Körper mit geringerer Betonung 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 Nutzung zu ermöglichen.

Ende der Theming-Ergebnisse mit angewendeten dynamischen Farben und Farbdesigns.
Nächste Schritte
Weitere Codelabs zum Compose-Lernpfad:
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