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.
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.
Endpunkt des Codelabs mit hellen und dynamischen Designs.
Endpunkt des Design-Codelabs mit dunklen und dynamischen Designs.
Voraussetzungen
- Die aktuelle Version von Android Studio
- Grundlegende Kenntnisse der Sprache Kotlin
- Grundlegendes zu Jetpack Compose
- Grundkenntnisse in Erstellungslayouts wie Zeile, Spalte und Modifikator
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 kennenlernen
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.
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 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.
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 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.
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.
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.
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 verwendet:
useDarkTheme
: Dieser Parameter ist mit der FunktionisSystemInDarkTheme()
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 anuseDarkTheme
ü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 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.
Hauptaktivität.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.
Hauptaktivität.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 Grunddesign (links).
App mit importiertem Farbdesign (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.
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.
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.
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.
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()
-Funktion 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.
Hauptaktivität.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.
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.
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.
Suchleiste mit Hintergrundfarbe auf der Tonfläche.
Farben der unverankerten Aktionsschaltflächen
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
)
){
/*..*/
}
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.
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
)
}
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.
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.
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.
Schriftskala Material 3.
Typografie definieren
In Compose gibt es neben den vorhandenen Klassen TextStyle
und font-related
die M3-Klasse Typography
, um die Schriftskala Material 3 zu modellieren.
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.
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.k
t 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 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
)
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
)
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. Das Motiv wird 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
),
...
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 */}
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:
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
}
}
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.
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:
- 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.
- 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.
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-Design mit Compose mit Farben, Typografie und Formen sowie dynamischen Farben implementiert, um Ihre Anwendung zu personalisieren und ein personalisiertes Erlebnis zu bieten.
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
- Leitfaden zum Verfassen von Designs
- Material-Designs für das Schreiben
Beispiel-Apps
- Beispiel-App für Antworten mit vollständigem Material 3-Thema
- JetChat demonstriert dynamische Themen