1. Introduzione
In questo codelab, imparerai a creare temi per le tue app in Jetpack Compose utilizzando Material Design 3. Scoprirai anche i componenti fondamentali degli schemi di colori, della tipografia e delle forme di Material Design 3, che ti aiutano a personalizzare e rendere accessibile il tema della tua applicazione.
Inoltre, esplorerai il supporto dei temi dinamici insieme a diversi livelli di enfasi.
Cosa imparerai a fare
In questo codelab imparerai:
- Aspetti chiave dei temi Material 3
- Combinazioni di colori Material 3 e come generare temi per la tua app
- Come supportare i temi dinamici e chiari/scuri per la tua app
- Tipografia e forme per personalizzare l'app
- Componenti Material 3 e personalizzazione per applicare stili alla tua app
Cosa creerai
In questo codelab, applicherai un tema a un'app client di posta elettronica chiamata Reply. Inizierai con un'applicazione senza stili, utilizzando il tema di base, e applicherai ciò che impari per applicare il tema all'applicazione e supportare i temi scuri.

Punto di partenza predefinito della nostra app con il tema di base.
Creerai il tema con combinazione di colori, tipografia e forme, per poi applicarlo alla mailing list e alla pagina dei dettagli della tua app. Aggiungerai anche il supporto del tema dinamico all'app. Al termine del codelab, avrai il supporto sia per i temi a colori che per quelli dinamici per la tua app.

Punto di arrivo del codelab sui temi con tema cromatico chiaro e tema dinamico chiaro.

Punto finale del codelab sui temi con temi di colore scuro e temi dinamici scuri.
Che cosa ti serve
- La versione più recente di Android Studio
- Esperienza di base con il linguaggio Kotlin
- Conoscenza di base di Jetpack Compose
- Familiarità di base con i layout di Compose, come Row, Column e Modifier
2. Preparazione
In questo passaggio, scarichi il codice completo dell'app Reply che personalizzerai in questo codelab.
Ottieni il codice
Il codice per questo codelab è disponibile nel repository GitHub android-compose-codelabs. Per clonarlo, esegui:
$ git clone https://github.com/googlecodelabs/android-compose-codelabs
In alternativa, puoi scaricare due file ZIP:
Dai un'occhiata all'app di esempio
Il codice che hai appena scaricato contiene il codice per tutti i codelab di Compose disponibili. Per completare questo codelab, apri il progetto ThemingCodelab in Android Studio.
Ti consigliamo di iniziare con il codice nel ramo principale e di seguire il codelab passo dopo passo al tuo ritmo. In qualsiasi momento, puoi eseguire una delle due versioni in Android Studio modificando il ramo Git del progetto.
Esplorare il codice iniziale
Il codice principale contiene un pacchetto UI, che include i seguenti pacchetti e file principali con cui interagire:
MainActivity.kt: attività del punto di ingresso in cui avvii l'app Reply.com.example.reply.ui.theme: questo pacchetto contiene temi, tipografia e combinazioni di colori. In questo pacchetto aggiungerai i temi Material.com.example.reply.ui.components: contiene i componenti personalizzati dell'app, come elementi di elenco, barre delle app e così via. Applicherai i temi a questi componenti.ReplyApp.kt: questa è la nostra funzione componibile principale in cui inizierà l'albero della UI. In questo file applicherai i temi di primo livello.
Questo codelab si concentrerà sui file del pacchetto ui.
3. Tematizzazione di Material 3
Jetpack Compose offre un'implementazione di Material Design, un sistema di progettazione completo per la creazione di interfacce digitali. I componenti di Material Design (pulsanti, schede, interruttori e così via) sono basati su Material Theming, un modo sistematico per personalizzare Material Design in modo da riflettere meglio il brand del tuo prodotto.
Il tema Material 3 comprende i seguenti sottosistemi per aggiungere temi alla tua app: combinazione di colori, tipografia e forme. Quando personalizzi questi valori, le modifiche vengono automaticamente riportate nei componenti M3 che utilizzi per creare la tua app. Analizziamo ogni sottosistema e implementiamolo nell'app di esempio.

Sottosistema Material 3 di colori, tipografia e forme.
4. Palette colori
La base di una combinazione di colori è il set di cinque colori chiave, ognuno dei quali si riferisce a una tavolozza tonale di 13 tonalità utilizzate dai componenti Material 3.

Cinque colori chiave di base per creare un tema M3.
Ogni colore intenso (primario, secondario e terziario) viene quindi fornito in quattro colori compatibili di tonalità diverse per l'abbinamento, la definizione dell'enfasi e l'espressione visiva.

Quattro colori tonali dei colori di accento di base primari, secondari e terziari.
Allo stesso modo, anche i colori neutri sono suddivisi in quattro tonalità compatibili utilizzate per le superfici e lo sfondo. Sono importanti anche per mettere in evidenza le icone di testo quando vengono posizionate su qualsiasi superficie.

Quattro colori tonali di colori neutri di base.
Scopri di più su Combinazione di colori e ruoli dei colori.
Generazione di combinazioni di colori
Anche se puoi creare manualmente un ColorScheme personalizzato, spesso è più facile generarlo utilizzando i colori di origine del tuo brand. Lo strumento Material Theme Builder ti consente di farlo e, se vuoi, di esportare il codice di tematizzazione di Compose.
Puoi scegliere il colore che preferisci, ma per il nostro caso d'uso utilizzerai il colore primario predefinito di Rispondi #825500. Fai clic sul colore Principale nella sezione Colori principali a sinistra e aggiungi il codice nel selettore di colori.

Aggiunta del codice colore principale in Material Theme Builder.
Dopo aver aggiunto il colore principale in Material Theme Builder, dovresti visualizzare il seguente tema e l'opzione per l'esportazione nell'angolo in alto a destra. Per questo codelab, esporta il tema in Jetpack Compose.

Strumento di creazione di temi Material con l'opzione di esportazione nell'angolo in alto a destra.
Il colore primario #825500 genera il seguente tema che aggiungerai all'app. Material 3 offre un'ampia gamma di ruoli di colore per esprimere in modo flessibile lo stato, l'importanza e l'enfasi di un componente.

Combinazione di colori chiari e scuri esportata dal colore principale.
Il file The Color.kt generato contiene i colori del tema con tutti i ruoli definiti per i colori del tema chiaro e scuro.
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)
Il file The Theme.kt generato contiene una configurazione per schemi di colori chiari e scuri e il tema dell'app. Contiene anche la funzione componibile principale per la creazione di temi, 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
)
}
L'elemento principale per implementare i temi in Jetpack Compose è il composable MaterialTheme.
Devi racchiudere il composable MaterialTheme() nella funzione AppTheme(), che accetta due parametri:
useDarkTheme: questo parametro è collegato alla funzioneisSystemInDarkTheme()per osservare le impostazioni dei temi di sistema e applicare il tema chiaro o scuro. Se vuoi mantenere manualmente la tua app in un tema chiaro o scuro, puoi passare un valore booleano auseDarkTheme.content: i contenuti a cui verrà applicato il tema.
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
val colors = if (!useDarkTheme) {
LightColors
} else {
DarkColors
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
Se provi a eseguire l'app ora, dovresti vedere che ha lo stesso aspetto. Anche se hai importato la nostra nuova combinazione di colori con nuovi colori del tema, visualizzi comunque il tema di base perché non hai applicato il tema all'app Crea.

App con tema di base quando non viene applicato alcun tema.
Per applicare il nuovo tema, in MainActivity.kt, racchiudi il composable principale ReplyApp con la funzione di gestione dei temi principale, AppTheme().
MainActivity.kt
setContent {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
AppTheme {
ReplyApp(/*..*/)
}
}
Aggiornerai anche le funzioni di anteprima per visualizzare il tema applicato alle anteprime delle app. Racchiudi il composable ReplyApp all'interno di ReplyAppPreview() con AppTheme per applicare i temi alle anteprime.
Nei parametri di anteprima sono definiti sia il tema chiaro che quello scuro del sistema, quindi vedrai entrambe le anteprime.
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
)
)
}
}
Se esegui l'app ora, dovresti vedere le anteprime dell'app con i colori del tema importato anziché il tema di base.

App con tema di base (a sinistra).
App con tema cromatico importato (a destra).

Anteprime delle app chiare e scure con temi di colore importati.
Material 3 supporta sia le combinazioni di colori chiare che scure. Hai eseguito il wrapping dell'app solo con il tema importato; i componenti Material 3 utilizzano i ruoli di colore predefiniti.
Scopriamo i ruoli e l'utilizzo dei colori prima di iniziare ad aggiungerli all'app.
Ruoli dei colori e accessibilità
Ogni ruolo del colore può essere utilizzato in una serie di posizioni a seconda dello stato, dell'importanza e dell'enfasi del componente.

Ruoli dei colori primari, secondari e terziari.
Primario è il colore di base, utilizzato per i componenti principali come i pulsanti in evidenza e gli stati attivi.
Il colore secondario dei tasti viene utilizzato per i componenti meno importanti dell'interfaccia utente, ad esempio i chip di filtro.
Il colore chiave terziario viene utilizzato per fornire accenti contrastanti, mentre i colori neutri vengono utilizzati per lo sfondo e le superfici dell'app.
Il sistema di colori di Material fornisce valori di tonalità e misurazioni standard che possono essere utilizzati per soddisfare i rapporti di contrasto accessibili. Utilizza on-primary sopra primary, on-primary-container sopra primary-container e così via per gli altri colori neutri e di accento per fornire un contrasto accessibile all'utente.
Per saperne di più, consulta Ruoli dei colori e accessibilità.
Elevazioni tonali e delle ombre
Material 3 rappresenta l'elevazione principalmente utilizzando overlay di colore tonale. Questo è un nuovo modo per differenziare i contenitori e le superfici tra loro. L'aumento dell'elevazione tonale utilizza un tono più prominente, oltre alle ombre.
Elevazione tonale al livello 2 che prende il colore dallo spazio del colore principale.
Anche le sovrapposizioni di elevazione nei temi scuri sono state sostituite da sovrapposizioni di colori tonali in Material Design 3. Il colore della sovrapposizione proviene dallo spazio del colore principale.
Surface, il componente componibile di base dietro la maggior parte dei componenti M3, include il supporto per l'elevazione tonale e dell'ombreggiatura:
Surface(
modifier = modifier,
tonalElevation = {..}
shadowElevation = {..}
) {
Column(content = content)
}
Aggiungere colori all'app
Se esegui l'app, puoi vedere i colori esportati visualizzati nell'app in cui i componenti assumono i colori predefiniti. Ora che conosciamo i ruoli e l'utilizzo dei colori, applichiamo il tema all'app con i ruoli dei colori corretti.

App con tema cromatico e componenti che assumono ruoli di colore predefiniti.
Colori della superficie
Nella schermata Home, inizierai inserendo il composable dell'app principale in un Surface() per fornire la base su cui posizionare i contenuti dell'app. Apri MainActivity.kt e racchiudi il componibile ReplyApp() con Surface.
Fornirai anche un'elevazione tonale di 5 dp per dare alla superficie un colore tonale dello slot principale, che contribuisce a fornire contrasto con la voce di elenco e la barra di ricerca in alto. Per impostazione predefinita, l'elevazione tonale e dell'ombra per la superficie è 0 dp.
MainActivity.kt
AppTheme {
Surface(tonalElevation = 5.dp) {
ReplyApp(
replyHomeUIState = uiState,
// other parameters
)
}
}
Se esegui l'applicazione ora e vedi sia la pagina Elenco che quella Dettagli, dovresti vedere la superficie tonale applicata all'intera app.

Sfondo dell'app senza colore di superficie e tonale (a sinistra).
Sfondo dell'app con colore di superficie e tonale applicato (a destra).
Colori della barra dell'app
La nostra barra di ricerca personalizzata in alto non ha uno sfondo trasparente come richiesto dal design. Per impostazione predefinita, viene ripristinata la superficie di base predefinita. Puoi fornire uno sfondo per creare una separazione chiara.

Barra di ricerca personalizzata senza sfondo (a sinistra).
Barra di ricerca personalizzata con uno sfondo (a destra).
Ora modificherai ui/components/ReplyAppBars.kt, che contiene la barra delle app. Aggiungerai MaterialTheme.colorScheme.background al Modifier di Row Composable.
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
}
}
Ora dovresti vedere una chiara separazione tra la superficie tonale e la barra delle app con il colore di sfondo.

Barra di ricerca con colore di sfondo sopra la superficie tonale.
Colori del Floating Action Button (FAB)

FAB grande senza alcun tema applicato (a sinistra).
Pulsante di azione rapida grande a tema con colore terziario (a destra).
Nella schermata Home, puoi migliorare l'aspetto del Floating Action Button (FAB) in modo che si distingua come pulsante di invito all'azione. Per implementarlo, applica un colore intenso terziario.
Nel file ReplyListContent.kt, aggiorna containerColor per il pulsante di azione rapida al colore tertiaryContainer e il colore dei contenuti a onTertiaryContainer per mantenere l'accessibilità e il contrasto di colore.
ReplyListContent.kt
ReplyInboxScreen(/*..*/) {
// Email list content
LargeFloatingActionButton(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer
){
/*..*/
}
}
Esegui l'app per visualizzare il FAB a tema. Per questo codelab, utilizzerai un LargeFloatingActionButton.
Colori della scheda
La mailing list nella schermata Home utilizza un componente scheda. Per impostazione predefinita, è una scheda riempita che utilizza il colore della variante della superficie per il colore del contenitore, in modo da separare chiaramente il colore della superficie da quello della scheda. Compose fornisce anche implementazioni di ElevatedCard e OutlinedCard.
Puoi evidenziare ulteriormente alcuni elementi importanti fornendo tonalità di colore secondarie. Modificherai ui/components/ReplyEmailListItem.kt aggiornando il colore del contenitore della scheda utilizzando CardDefaults.cardColors() per le email importanti:
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
)
){
/*..*/
}

Evidenzia l'elemento dell'elenco utilizzando il colore del contenitore secondario sulla superficie tonale.
Colore elemento elenco dettagli
Ora hai personalizzato la schermata Home. Dai un'occhiata alla pagina dei dettagli facendo clic su uno qualsiasi degli elementi dell'elenco email.

Pagina dei dettagli predefinita senza voce di elenco a tema (a sinistra).
Voce di elenco dettagliata con applicazione del tema di sfondo (a destra).
All'elemento dell'elenco non è stato applicato alcun colore, pertanto viene ripristinato il colore della superficie tonale predefinito. Applicherai il colore di sfondo alla voce di elenco per creare una separazione e aggiungere un riempimento per fornire spazio intorno allo sfondo.
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
}
}
Come puoi vedere, fornendo lo sfondo, hai una chiara separazione tra la superficie tonale e la voce di elenco.
Ora hai sia la home page che le pagine dei dettagli con ruoli e utilizzo dei colori corretti . Scopriamo come la tua app può sfruttare i colori dinamici per offrire un'esperienza ancora più personalizzata e coesa.
5. Aggiunta di colori dinamici nell'app
Il colore dinamico è la parte fondamentale di Material 3, in cui un algoritmo deriva colori personalizzati dallo sfondo di un utente da applicare alle app e all'UI di sistema.
I temi dinamici rendono le tue app più personalizzate. Inoltre, offre agli utenti un'esperienza coerente e senza interruzioni con il tema del sistema.
Il colore dinamico è disponibile su Android 12 e versioni successive. Se il colore dinamico è disponibile, puoi configurare una combinazione di colori dinamica utilizzando dynamicDarkColorScheme() o dynamicLightColorScheme(). In caso contrario, devi ripiegare sull'utilizzo di un ColorScheme chiaro o scuro predefinito.
Sostituisci il codice della funzione AppTheme nel file Theme.kt con quello riportato di seguito:
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
)
}

Tema dinamico tratto dallo sfondo di Android 13.
Se esegui l'app ora, dovresti vedere l'applicazione dei temi dinamici utilizzando lo sfondo predefinito di Android 13.
Potresti anche voler che la barra di stato venga stilizzata in modo dinamico a seconda della combinazione di colori utilizzata per il tema dell'app.

App senza colore della barra di stato applicato (a sinistra).
App con il colore della barra di stato applicato (a destra).
Per aggiornare il colore della barra di stato in base al colore primario del tema, aggiungi il colore della barra di stato dopo la selezione della combinazione di colori nel composable AppTheme:
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
)
}
Quando esegui l'app, dovresti vedere la barra di stato che assume il tema del colore principale. Puoi anche provare i temi dinamici chiari e scuri modificando il tema scuro del sistema.

Tema dinamico chiaro (a sinistra) e scuro (a destra) applicato con lo sfondo predefinito di Android 13.
Finora hai applicato colori alla tua app che ne hanno migliorato l'aspetto. Tuttavia, puoi notare che tutto il testo nell'app ha le stesse dimensioni, quindi ora puoi aggiungere la tipografia all'app.
6. Tipografia
Material Design 3 definisce una scala tipografica. La denominazione e il raggruppamento sono stati semplificati in: display, titolo, corpo e etichetta, con dimensioni grandi, medie e piccole per ciascuno.

Scala tipografica Material 3.
Definizione della tipografia
Compose fornisce la classe Typography di M3, insieme alle classi TextStyle e font-related esistenti, per modellare la scala tipografica di Material 3.
Il costruttore di tipografia offre valori predefiniti per ogni stile, in modo da poter omettere i parametri che non vuoi personalizzare. Per saperne di più, consulta gli stili tipografici e i relativi valori predefiniti.
Nella tua app utilizzerai cinque stili tipografici: headlineSmall, titleLarge, bodyLarge, bodyMedium e labelMedium. Questi stili copriranno sia la schermata Home che quella dei dettagli.

Schermata che mostra l'utilizzo della tipografia per lo stile di titolo, etichetta e corpo.
Dopodiché, vai al pacchetto ui/theme e apri Type.kt. Aggiungi il seguente codice per fornire la tua implementazione per alcuni stili di testo anziché i valori predefiniti:
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
)
)
La tipografia è ora definita. Per aggiungerlo al tema, passalo al componibile MaterialTheme() all'interno di AppTheme:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
// dynamic theming content
MaterialTheme(
colorScheme = colors,
typography = typography,
content = content
)
}
Utilizzo della tipografia
Come per i colori, puoi accedere allo stile tipografico del tema corrente utilizzando MaterialTheme.typography. In questo modo, puoi utilizzare tutte le tipografie definite in Type.k.
Text(
text = "Hello M3 theming",
style = MaterialTheme.typography.titleLarge
)
Text(
text = "you are learning typography",
style = MaterialTheme.typography.bodyMedium
)
Probabilmente il tuo prodotto non avrà bisogno di tutti i 15 stili predefiniti della scala tipografica Material Design. In questo codelab vengono scelte cinque dimensioni, mentre le altre vengono omesse.
Poiché non hai applicato la tipografia ai composable Text(, tutto il testo torna a Typography.bodyLarge per impostazione predefinita.
Tipografia dell'elenco della casa
Successivamente, applica la tipografia alla funzione ReplyEmailListItem in ui/components/ReplyEmailListItem.kt per creare una distinzione tra titoli ed etichette:
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
)

Schermata Home senza tipografia applicata (a sinistra).
Schermata Home con la tipografia applicata (a destra).
Tipografia dell'elenco dettagli
Allo stesso modo, aggiungerai la tipografia nella schermata dei dettagli aggiornando tutti i composable di testo di ReplyEmailThreadItem in ui/components/ReplyEmailThreadItem.kt:
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
)

Schermata dei dettagli senza tipografia applicata (a sinistra).
Schermata dei dettagli con la tipografia applicata (a destra).
Personalizzare la tipografia
Con Compose è molto facile personalizzare lo stile del testo o fornire il tuo carattere personalizzato. Puoi modificare TextStyle per personalizzare il tipo di carattere, la famiglia di caratteri, la spaziatura tra le lettere e così via.
Modificherai lo stile del testo nel file theme/Type.kt, che verrà applicato a tutti i componenti che lo utilizzano.
Aggiorna fontWeight a SemiBold e lineHeight a 32.sp per titleLarge, che viene utilizzato per l'oggetto nell'elemento di elenco. Verrà data maggiore enfasi all'argomento e verranno fornite separazioni chiare.
Type.kt
...
titleLarge = TextStyle(
fontWeight = FontWeight.SemiBold,
fontSize = 18.sp,
lineHeight = 32.sp,
letterSpacing = 0.0.sp
),
...

Applicazione di una tipografia personalizzata al testo dell'oggetto.
7. Forme
Le superfici dei materiali possono essere visualizzate in diverse forme. Le forme attirano l'attenzione, identificano i componenti, comunicano lo stato ed esprimono il brand.
Definizione delle forme
Compose fornisce la classe Shapes con parametri espansi per implementare nuove forme M3. La scala delle forme M3, simile alla scala tipografica, consente di utilizzare una gamma espressiva di forme nell'intera UI.
Nella scala delle forme sono disponibili diverse dimensioni:
- Molto ridotta
- Small
- Medium
- Grande
- Molto grande
Per impostazione predefinita, ogni forma ha un valore predefinito che può essere sostituito. Per la tua app, utilizzerai la forma media per modificare la voce di elenco, ma puoi dichiarare anche altre forme. Crea un nuovo file denominato Shape.kt nel pacchetto ui/theme e aggiungi il codice per le forme:
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)
)
Ora che hai definito il shapes, passalo a M3 MaterialTheme come hai fatto per colori e tipografia:
Theme.kt
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable() () -> Unit
) {
// dynamic theming content
MaterialTheme(
colorScheme = colors,
typography = typography,
shapes = shapes
content = content
)
}
Utilizzo delle forme
Proprio come per il colore e la tipografia, puoi applicare le forme ai componenti Material utilizzando MaterialTheme.shape, che ti fornisce l'istanza Shape per accedere alle forme Material.
A molti componenti Material sono già applicate forme predefinite, ma puoi fornire e applicare le tue forme ai componenti tramite gli slot disponibili.
Card(shape = MaterialTheme.shapes.medium) { /* card content */ }
FloatingActionButton(shape = MaterialTheme.shapes.large) { /* fab content */}
Mappatura dei componenti Material utilizzando diversi tipi di forme.
Puoi vedere il mapping delle forme per tutti i componenti nella documentazione relativa alle forme.
Sono disponibili altre due forme da utilizzare, RectangleShape e CircleShape, che fanno parte di Compose. La forma rettangolare non ha raggio del bordo, mentre la forma circolare mostra i bordi completamente arrotondati.
Puoi anche applicare forme ai componenti utilizzando Modifiers che accettano forme, come Modifier.clip, Modifier.background e Modifier.border.
Forma della barra dell'app
Vogliamo che la barra dell'app abbia uno sfondo con angoli arrotondati:

TopAppBar utilizza un Row con un colore di sfondo. Per ottenere lo sfondo con angoli arrotondati, definisci la forma dello sfondo passando CircleShape al modificatore dello sfondo:
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
}
}

Forma dell'elemento dell'elenco dettagli
Nella schermata Home, stai utilizzando una scheda che utilizza Shape.Medium per impostazione predefinita. Tuttavia, per la pagina dei dettagli, hai utilizzato una colonna con colore di sfondo. Per un aspetto uniforme dell'elenco, applica una forma media.

Colonna dell'elenco dettagli senza forma nell'elemento dell'elenco (a sinistra) e forma media nell'elenco (a destra).
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
}
}
Ora, l'esecuzione dell'app mostra un elemento di elenco di schermate dettagliato a forma di medium.
8. Enfasi
L'enfasi nell'interfaccia utente ti aiuta a evidenziare alcuni contenuti rispetto ad altri, ad esempio quando vuoi differenziare il titolo dai sottotitoli codificati. L'enfasi in M3 utilizza variazioni di colore e le relative combinazioni. Esistono due modi per aggiungere enfasi:
- Utilizzo di superficie, variante della superficie e sfondo insieme ai colori sulla superficie e alle varianti della superficie del sistema di colori M3 espanso.
Ad esempio, la superficie può essere utilizzata con la variante sulla superficie e la variante della superficie può essere utilizzata con sulla superficie per fornire diversi livelli di enfasi.
Le varianti di superficie possono essere utilizzate anche con i colori intensi per fornire meno enfasi rispetto ai colori intensi, ma rimanere comunque accessibili e rispettare il rapporto di contrasto.

Ruoli di colore di superficie, sfondo e variante di superficie.
- Utilizzo di spessori diversi per il testo. Come hai visto nella sezione Tipografia, puoi fornire pesi personalizzati alla scala tipografica per enfatizzare in modo diverso.
Successivamente, aggiorna ReplyEmailListItem.kt per fornire una differenza di enfasi utilizzando la variante di superficie. Per impostazione predefinita, il contenuto della scheda assume il colore predefinito in base allo sfondo.
Aggiornerai il colore del testo dell'ora e del corpo del testo del componibile a onSurfaceVariant. In questo modo, l'enfasi viene ridotta rispetto a onContainerColors, che viene applicato ai composable di testo del soggetto e del titolo per impostazione predefinita.

Ora e corpo del testo con la stessa enfasi rispetto all'oggetto e al titolo (a sinistra).
Ora e corpo con enfasi ridotta rispetto a oggetto e titolo (a destra).
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
)
Per la scheda email importante con lo sfondo secondaryContainer, il colore di tutto il testo è onSecondaryContainer per impostazione predefinita. Per le altre email, lo sfondo è surfaceVariant,, quindi tutto il testo è impostato sul colore onSurfaceVariant per impostazione predefinita.
9. Complimenti
Complimenti! Hai completato correttamente questo codelab. Hai implementato i temi Material con Compose utilizzando colori, tipografia e forme, oltre a colori dinamici per applicare temi alla tua applicazione e offrire un'esperienza personalizzata.

Fine dei risultati della tematizzazione con colori dinamici e tema cromatico applicato.
Passaggi successivi
Dai un'occhiata agli altri nostri codelab nel percorso di apprendimento di Compose:
- Nozioni di base sulla composizione
- Layout di composizione
- Stato in Compose
- Comporre per le app esistenti
Per approfondire
- Guida ai temi di Compose
- Temi di Material per Compose
App di esempio
- App Reply sample con tematizzazione Material 3 completa
- JetChat che mostra i temi dinamici