Material Design 3 in Compose

Jetpack Compose offre un'implementazione di Material You e Material 3 Expressive, la nuova evoluzione di Material Design. M3 Expressive è un'espansione di Material Design 3, che include aggiornamenti basati su ricerche relative a temi, componenti, movimento, tipografia e altro ancora, tutti progettati per aiutarti a creare prodotti accattivanti e desiderabili che gli utenti adorano. Supporta anche le funzionalità di personalizzazione di Material You, come il colore dinamico. M3 Expressive si integra con lo stile visivo e l'UI di sistema di Android 16.

Di seguito mostriamo l'implementazione di Material Design 3 utilizzando l'app di esempio Reply. L'esempio Reply si basa interamente su Material Design 3.

App di esempio Reply che utilizza Material Design 3
Figura 1. App di esempio Reply che utilizza Material Design 3

Dipendenza

Per iniziare a utilizzare Material 3 nella tua app Compose, aggiungi la dipendenza Compose Material 3 ai file build.gradle:

implementation "androidx.compose.material3:material3:$material3_version"

Una volta aggiunta la dipendenza, puoi iniziare ad aggiungere alle tue app i sistemi di Material Design, tra cui colore, tipografia e forma.

API sperimentali

Alcune API M3 sono considerate sperimentali. In questi casi, devi attivare l'opzione a livello di funzione o file utilizzando l'annotazione ExperimentalMaterial3Api:

// import androidx.compose.material3.ExperimentalMaterial3Api
@Composable
fun AppComposable() {
    // M3 composables
}

Temi di Material

Un tema M3 contiene i seguenti sottosistemi: combinazione di colori, tipografia e forme. Quando personalizzi questi valori, le modifiche vengono applicate automaticamente ai componenti M3 che utilizzi per creare la tua app.

Sottosistemi di Material Design: colore, tipografia e forme
Figura 2. Sottosistemi di Material Design: colore, tipografia e forme

Jetpack Compose implementa questi concetti con il componibile MaterialTheme di M3:

MaterialTheme(
    colorScheme = /* ...
    typography = /* ...
    shapes = /* ...
) {
    // M3 app content
}

Per applicare un tema ai contenuti della tua applicazione, definisci la combinazione di colori, la tipografia e le forme specifiche della tua app.

Combinazione di colori

La base di una combinazione di colori è l'insieme dei cinque colori chiave. Ognuno di questi colori è correlato a una tavolozza di 13 tonalità, utilizzate dai componenti di Material 3. Ad esempio, questa è la combinazione di colori per il tema chiaro per Reply:

Combinazione di colori chiari dell'app di esempio Reply
Figura 3. Combinazione di colori chiari dell'app di esempio Reply

Scopri di più sulla combinazione di colori e sui ruoli dei colori.

Genera combinazioni di colori

Sebbene sia possibile creare manualmente un ColorScheme personalizzato, spesso è più facile generarne uno utilizzando i colori di origine del tuo brand. Lo strumento Material Theme Builder ti consente di farlo e, facoltativamente, di esportare il codice dei temi di Material di Compose. Vengono generati i seguenti file:

  • Color.kt contiene i colori del tema con tutti i ruoli definiti per i colori del tema chiaro e scuro.

val md_theme_light_primary = Color(0xFF476810)
val md_theme_light_onPrimary = Color(0xFFFFFFFF)
val md_theme_light_primaryContainer = Color(0xFFC7F089)
// ..
// ..

val md_theme_dark_primary = Color(0xFFACD370)
val md_theme_dark_onPrimary = Color(0xFF213600)
val md_theme_dark_primaryContainer = Color(0xFF324F00)
// ..
// ..

  • Theme.kt contiene una configurazione per le combinazioni di colori chiari e scuri e il tema dell'app.

private val LightColorScheme = lightColorScheme(
    primary = md_theme_light_primary,
    onPrimary = md_theme_light_onPrimary,
    primaryContainer = md_theme_light_primaryContainer,
    // ..
)
private val DarkColorScheme = darkColorScheme(
    primary = md_theme_dark_primary,
    onPrimary = md_theme_dark_onPrimary,
    primaryContainer = md_theme_dark_primaryContainer,
    // ..
)

@Composable
fun ReplyTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colorScheme =
        if (!darkTheme) {
            LightColorScheme
        } else {
            DarkColorScheme
        }
    MaterialTheme(
        colorScheme = colorScheme,
        content = content
    )
}

Per supportare i temi chiaro e scuro, utilizza isSystemInDarkTheme(). In base all'impostazione di sistema, definisci la combinazione di colori da utilizzare: chiara o scura.

Combinazioni di colori dinamiche

Il colore dinamico è la parte fondamentale di Material You, in cui un algoritmo ricava colori personalizzati dallo sfondo di un utente da applicare alle sue app e alla UI di sistema. Questa tavolozza dei colori viene utilizzata come punto di partenza per generare combinazioni di colori chiari e scuri.

Temi dinamici dell'app di esempio Reply dallo sfondo (a sinistra) e temi predefiniti dell'app (a destra)
Figura 4. Temi dinamici dell'app di esempio Reply dallo sfondo (a sinistra) e temi predefiniti dell'app (a destra)

Il colore dinamico è disponibile su Android 12 e versioni successive. Se il colore dinamico è disponibile, puoi configurare un ColorScheme dinamico. In caso contrario, dovresti utilizzare un ColorScheme chiaro o scuro personalizzato.

ColorScheme fornisce funzioni di creazione per creare una combinazione di colori dinamica chiara o scura:

// Dynamic color is available on Android 12+
val dynamicColor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val colors = when {
    dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
    dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
    darkTheme -> DarkColorScheme
    else -> LightColorScheme
}

Utilizzo del colore

Puoi accedere ai colori dei temi di Material nella tua app tramite MaterialTheme.colorScheme:

Text(
    text = "Hello theming",
    color = MaterialTheme.colorScheme.primary
)

Ogni ruolo colore può essere utilizzato in vari punti a seconda dello stato, della prominenza e dell'enfasi del componente.

  • Il colore principale è il colore di base, utilizzato per i componenti principali come i pulsanti in evidenza, gli stati attivi e la tinta delle superfici in rilievo.
  • Il colore della chiave secondaria viene utilizzato per i componenti meno visibili nell'interfaccia utente, come i chip di filtro, e amplia le possibilità di espressione del colore.
  • Il colore chiave terziario viene utilizzato per ricavare i ruoli degli accenti di contrasto che possono essere utilizzati per bilanciare i colori primari e secondari o per attirare maggiormente l'attenzione su un elemento.

Il design dell'app di esempio Reply utilizza il colore on-primary-container sopra primary-container per mettere in evidenza l'elemento selezionato.

Contenitore principale e campi di testo con colore on-primary-container.
Figura 5. Contenitore principale e campi di testo con colore on-primary-container.

Card(
    colors = CardDefaults.cardColors(
        containerColor =
        if (isSelected) MaterialTheme.colorScheme.primaryContainer
        else
            MaterialTheme.colorScheme.surfaceVariant
    )
) {
    Text(
        text = "Dinner club",
        style = MaterialTheme.typography.bodyLarge,
        color =
        if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer
        else MaterialTheme.colorScheme.onSurface,
    )
}

Qui puoi vedere nel riquadro di navigazione a scomparsa di Reply come i colori dei container secondari e terziari vengono utilizzati in contrasto per creare enfasi e accento.

Combinazione di container terziario e on-tertiary-container per il Floating Action Button (FAB).
Figura 6. Combinazione di container terziario e on-tertiary-container per il Floating Action Button (FAB).

Tipografia

Material Design 3 definisce una scala dei caratteri, inclusi gli stili di testo adattati da Material Design 2. La denominazione e il raggruppamento sono stati semplificati in: display, headline, title, body e label, con dimensioni grandi, medie e piccole per ciascuno.

Scala tipografica predefinita per Material Design 3
Figura 7. Scala tipografica predefinita per Material Design 3
M3 Dimensione carattere/altezza riga predefinita
displayLarge Roboto 57/64
displayMedium Roboto 45/52
displaySmall Roboto 36/44
headlineLarge Roboto 32/40
headlineMedium Roboto 28/36
headlineSmall Roboto 24/32
titleLarge New- Roboto Medium 22/28
titleMedium Roboto Medium 16/24
titleSmall Roboto Medium 14/20
bodyLarge Roboto 16/24
bodyMedium Roboto 14/20
bodySmall Roboto 12/16
labelLarge Roboto Medium 14/20
labelMedium Roboto Medium 12/16
labelSmall New Roboto Medium, 11/16

Definisci la tipografia

Compose fornisce la classe Typography di M3, insieme alle classi esistenti TextStyle e relative ai caratteri, per modellare la scala dei tipi di Material 3. Il costruttore Typography offre valori predefiniti per ogni stile, in modo da poter omettere i parametri che non vuoi personalizzare:

val replyTypography = Typography(
    titleLarge = TextStyle(
        fontWeight = FontWeight.SemiBold,
        fontSize = 22.sp,
        lineHeight = 28.sp,
        letterSpacing = 0.sp
    ),
    titleMedium = TextStyle(
        fontWeight = FontWeight.SemiBold,
        fontSize = 16.sp,
        lineHeight = 24.sp,
        letterSpacing = 0.15.sp
    ),
    // ..
)
// ..

Corpo grande, corpo medio ed etichetta media per un utilizzo diverso della tipografia.
Figura 8. Corpo grande, corpo medio ed etichetta media per diversi utilizzi della tipografia.

È probabile che il tuo prodotto non abbia bisogno di tutti i 15 stili predefiniti della scala tipografica di Material Design. In questo esempio, vengono scelte cinque dimensioni per un insieme ridotto, mentre le altre vengono omesse.

Puoi personalizzare la tipografia modificando i valori predefiniti di TextStyle e delle proprietà relative ai caratteri come fontFamily e letterSpacing.

bodyLarge = TextStyle(
    fontWeight = FontWeight.Normal,
    fontFamily = FontFamily.SansSerif,
    fontStyle = FontStyle.Italic,
    fontSize = 16.sp,
    lineHeight = 24.sp,
    letterSpacing = 0.15.sp,
    baselineShift = BaselineShift.Subscript
),

Dopo aver definito Typography, passalo a MaterialTheme di M3:

MaterialTheme(
    typography = replyTypography,
) {
    // M3 app Content
}

Utilizza gli stili di testo

Puoi recuperare la tipografia fornita al composable MaterialTheme di M3 utilizzando MaterialTheme.typography:

Text(
    text = "Hello M3 theming",
    style = MaterialTheme.typography.titleLarge
)
Text(
    text = "you are learning typography",
    style = MaterialTheme.typography.bodyMedium
)

Puoi scoprire di più sulle linee guida di Material sull'applicazione della tipografia.

Forme

Le superfici di Material possono essere visualizzate in forme diverse. Le forme indirizzano l'attenzione, identificano i componenti, comunicano lo stato ed esprimono il brand.

La scala delle forme definisce lo stile degli angoli dei contenitori, offrendo una gamma di arrotondamenti che va dal quadrato al cerchio completo.

Definisci le forme

Compose fornisce la classe Shapes di M3 con parametri espansi per supportare le nuove forme di M3. La scala delle forme di M3 è più simile alla scala dei caratteri, consentendo una gamma espressiva di forme nell'interfaccia utente.

Esistono diverse dimensioni delle forme:

  • Extra small
  • Piccolo
  • Media
  • Grandi
  • Extra large

Per impostazione predefinita, ogni forma ha un valore predefinito, ma puoi eseguirne l'override:

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

Dopo aver definito Shapes, puoi passarlo a MaterialTheme di M3:

MaterialTheme(
    shapes = replyShapes,
) {
    // M3 app Content
}

Utilizza le forme

Puoi personalizzare la scala della forma per tutti i componenti della MaterialTheme o puoi farlo per ogni singolo componente.

Applica la forma media e grande con i valori predefiniti:

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

Forma media per la scheda e forma grande per il Floating Action Button (FAB) nell'app di esempio Reply.
Figura 9. Forma media per la scheda e forma grande per il Floating Action Button (FAB) nell'app di esempio Reply

Esistono altre due forme, RectangleShape e CircleShape, che fanno parte di Compose. La forma rettangolare non ha un raggio del bordo, mentre la forma circolare mostra bordi completamente arrotondati:

Card(shape = RectangleShape) { /* card content */ }
Card(shape = CircleShape) { /* card content */ }

Gli esempi riportati di seguito mostrano alcuni dei componenti con i valori di forma predefiniti applicati:

Valori delle forme predefiniti per tutti i componenti di Material 3.
Figura 10. Valori delle forme predefiniti per tutti i componenti di Material 3.

Puoi scoprire di più sulle linee guida di Material per l'applicazione delle forme.

Enfasi

In M3, l'enfasi viene fornita utilizzando variazioni di colore e le relative combinazioni di colori. In M3, esistono due modi per aggiungere enfasi alla UI:

  • Utilizza i colori surface, surface-variant e background insieme ai colori on-surface e on-surface-variants del sistema di colori M3 espanso. Ad esempio, surface può essere utilizzato con on-surface-variant e surface-variant può essere utilizzato con on-surface per fornire diversi livelli di enfasi.
Utilizzare combinazioni di colori neutri per dare enfasi.
Figura 11. Utilizzo di combinazioni di colori neutri per enfatizzare.
  • Utilizzo di spessori dei caratteri diversi per il testo. In precedenza, hai visto che puoi fornire spessori personalizzati alla nostra scala dei caratteri per dare un'enfasi diversa.

bodyLarge = TextStyle(
    fontWeight = FontWeight.Bold
),
bodyMedium = TextStyle(
    fontWeight = FontWeight.Normal
)

Elevation

Material 3 rappresenta l'elevazione principalmente utilizzando overlay di colori tonali. Si tratta di un nuovo modo per differenziare i container e le superfici tra loro, oltre alle ombre: l'aumento dell'elevazione tonale utilizza un tono più evidente.

Elevazione tonale con elevazione dell'ombra
Figura 12. Elevazione tonale con elevazione dell'ombraE

Anche gli overlay di elevazione nei temi scuri sono stati modificati in overlay di colori tonali in Material 3. Il colore dell'overlay proviene dallo slot del colore principale.

Elevazione dell'ombra rispetto all'elevazione tonale in Material Design 3
Figura 13. Shadow elevation versus Tonal elevation in Material Design 3

Il componente componibile Surface di M3, che supporta la maggior parte dei componenti M3, include il supporto per l'elevazione tonale e dell'ombra:

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

Componenti di Material Design

Material Design include un ricco set di componenti Material (come pulsanti, chip, schede, barra di navigazione) che seguono già i temi di Material e ti aiutano a creare app Material Design accattivanti. Puoi iniziare a utilizzare i componenti con le proprietà predefinite fin da subito.

Button(onClick = { /*..*/ }) {
    Text(text = "My Button")
}

M3 fornisce molte versioni degli stessi componenti da utilizzare in ruoli diversi in base all'enfasi e all'attenzione.

Enfasi dei pulsanti da FAB, principale fino al pulsante di testo
Figura 14. Enfasi dei pulsanti da FAB, da pulsante principale a pulsante di testo
  • Un Floating Action Button (FAB) esteso per l'azione con la massima enfasi:

ExtendedFloatingActionButton(
    onClick = { /*..*/ },
    modifier = Modifier
) {
    Icon(
        imageVector = Icons.Default.Edit,
        contentDescription = stringResource(id = R.string.edit),
    )
    Text(
        text = stringResource(id = R.string.add_entry),
    )
}

  • Un pulsante pieno per un'azione ad alta enfasi:

Button(onClick = { /*..*/ }) {
    Text(text = stringResource(id = R.string.view_entry))
}

  • Un pulsante di testo per un'azione con enfasi bassa:

TextButton(onClick = { /*..*/ }) {
    Text(text = stringResource(id = R.string.replated_articles))
}

Puoi scoprire di più sui pulsanti e su altri componenti di Material. Material 3 offre un'ampia gamma di suite di componenti, come pulsanti, barre delle app e componenti di navigazione, progettati specificamente per diversi casi d'uso e dimensioni dello schermo.

Material fornisce anche diversi componenti di navigazione che ti aiutano a implementare la navigazione, a seconda delle diverse dimensioni e degli stati dello schermo.

NavigationBar viene utilizzato per i dispositivi compatti quando vuoi scegliere come target 5 o meno destinazioni:

NavigationBar(modifier = Modifier.fillMaxWidth()) {
    Destinations.entries.forEach { replyDestination ->
        NavigationBarItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { }
        )
    }
}

NavigationRail viene utilizzato per tablet o smartphone di dimensioni medio-piccole in modalità Orizzontale. Offre ergonomia agli utenti e migliora l'esperienza utente per questi dispositivi.

NavigationRail(
    modifier = Modifier.fillMaxHeight(),
) {
    Destinations.entries.forEach { replyDestination ->
        NavigationRailItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { }
        )
    }
}

Vetrina di Reply di BottomNavigationBar(a sinistra) e NavigationRail(a destra)
Figura 15. Esempio di risposta di BottomNavigationBar (a sinistra) e NavigationRail (a destra)

Rispondi utilizzando entrambi i temi predefiniti per offrire un'esperienza utente immersiva per tutte le dimensioni dei dispositivi.

NavigationDrawer viene utilizzato per i tablet di dimensioni medio-grandi in cui hai spazio sufficiente per mostrare i dettagli. Puoi utilizzare sia PermanentNavigationDrawer sia ModalNavigationDrawer insieme a NavigationRail.

PermanentNavigationDrawer(modifier = Modifier.fillMaxHeight(), drawerContent = {
    Destinations.entries.forEach { replyDestination ->
        NavigationRailItem(
            selected = selectedDestination == replyDestination,
            onClick = { },
            icon = { },
            label = { }
        )
    }
}) {
}

Vetrina di Reply del riquadro di navigazione a scomparsa permanente
Figura 16. Esempio di risposta del riquadro di navigazione a scomparsa permanente

Le opzioni di navigazione migliorano l'esperienza utente, l'ergonomia e la raggiungibilità. Puoi scoprire di più sui componenti di navigazione di Material nel codelab Compose Adaptive.

Personalizza i temi di un componente

M3 incoraggia la personalizzazione e la flessibilità. A tutti i componenti vengono applicati colori predefiniti, ma espongono API flessibili per personalizzare i colori, se necessario.

La maggior parte dei componenti, come schede e pulsanti, fornisce un oggetto predefinito che espone le interfacce di colore ed elevazione che possono essere modificate per personalizzare il componente:

val customCardColors = CardDefaults.cardColors(
    contentColor = MaterialTheme.colorScheme.primary,
    containerColor = MaterialTheme.colorScheme.primaryContainer,
    disabledContentColor = MaterialTheme.colorScheme.surface,
    disabledContainerColor = MaterialTheme.colorScheme.onSurface,
)
val customCardElevation = CardDefaults.cardElevation(
    defaultElevation = 8.dp,
    pressedElevation = 2.dp,
    focusedElevation = 4.dp
)
Card(
    colors = customCardColors,
    elevation = customCardElevation
) {
    // m3 card content
}

Puoi scoprire di più sulla personalizzazione di Material 3.

UI di sistema

Alcuni aspetti di Material You derivano dal nuovo stile visivo e dalla nuova UI di sistema di Android 12 e versioni successive. Due aree chiave in cui sono presenti modifiche sono l'effetto ripple e l'overscroll. Non è necessario alcun intervento aggiuntivo per implementare queste modifiche.

Onde

L'effetto onda ora utilizza un leggero scintillio per illuminare le superfici quando vengono premute. Compose Material Ripple utilizza un RippleDrawable della piattaforma in background su Android, quindi l'effetto onda scintillante è disponibile su Android 12 e versioni successive per tutti i componenti Material.

Ripple in M2 vs M3
Figura 17. Ripple in M2 versus M3

Overscroll

L'overscroll ora utilizza un effetto di allungamento sul bordo dei container di scorrimento. L'overscroll con allungamento è attivo per impostazione predefinita nei composabili dei container di scorrimento, ad esempio LazyColumn, LazyRow e LazyVerticalGrid, in Compose Foundation 1.1.0 e versioni successive, indipendentemente dal livello API.

Overscroll con effetto di allungamento sul bordo del container
Figura 18. Overscroll con effetto di allungamento sul bordo del container

Accessibilità

Gli standard di accessibilità integrati nei componenti Material sono progettati per fornire una base per la progettazione di prodotti inclusivi. Comprendere l'accessibilità del tuo prodotto può migliorare l'usabilità per tutti gli utenti, inclusi quelli con ipovisione, cecità, disabilità uditive, cognitive, motorie o situazionali (ad esempio un braccio rotto).

Accessibilità dei colori

Il colore dinamico è progettato per soddisfare gli standard di accessibilità per il contrasto di colore. Il sistema di tavolozze tonali è fondamentale per rendere accessibile qualsiasi combinazione di colori per impostazione predefinita.

Il sistema di colori di Material fornisce valori e misurazioni di tonalità standard che possono essere utilizzati per soddisfare i rapporti di contrasto accessibili.

App di esempio Reply: tavolozze di tonalità primarie, secondarie e terziarie (dall'alto verso il basso)
Figura 19. App di esempio Reply: tavolozze tonali primarie, secondarie e terziarie (dall'alto verso il basso)

Tutti i componenti Material e i temi dinamici utilizzano già i ruoli dei colori sopra indicati da un insieme di tavolozze di tonalità, selezionate per soddisfare i requisiti di accessibilità. Tuttavia, se personalizzi i componenti, assicurati di utilizzare i ruoli dei colori appropriati ed evita le discrepanze.

Utilizza on-primary sopra primary e on-primary-container sopra primary-container, e lo stesso per gli altri colori neutri e di contrasto per fornire un contrasto accessibile all'utente.

L'utilizzo di un contenitore terziario sopra quello principale offre all'utente un pulsante con un contrasto scarso:

// ✅ Button with sufficient contrast ratio
Button(
    onClick = { },
    colors = ButtonDefaults.buttonColors(
        containerColor = MaterialTheme.colorScheme.primary,
        contentColor = MaterialTheme.colorScheme.onPrimary
    )
) {
}

// ❌ Button with poor contrast ratio
Button(
    onClick = { },
    colors = ButtonDefaults.buttonColors(
        containerColor = MaterialTheme.colorScheme.tertiaryContainer,
        contentColor = MaterialTheme.colorScheme.primaryContainer
    )
) {
}

Contrasto sufficiente (a sinistra) e contrasto scarso (a destra)
Figura 20. Contrasto sufficiente (a sinistra) e contrasto scarso (a destra)

Accessibilità della tipografia

La scala dei tipi di M3 aggiorna la scala e i valori dei tipi statici per offrire un framework semplificato, ma dinamico, di categorie di dimensioni che si adattano ai dispositivi.

Ad esempio, in M3, a Display Small possono essere assegnati valori diversi a seconda del contesto del dispositivo, ad esempio uno smartphone o un tablet.

Schermi grandi

Material fornisce indicazioni sui layout adattivi e sui pieghevoli per rendere le tue app accessibili e migliorare l'ergonomia degli utenti che utilizzano dispositivi di grandi dimensioni.

Material offre diversi tipi di navigazione per aiutarti a offrire un'esperienza utente migliore per i dispositivi con schermi di grandi dimensioni.

Puoi scoprire di più sulle norme sulla qualità delle app per schermi di grandi dimensioni di Android e consultare il nostro esempio di risposta per un design adattivo e accessibile.

Scopri di più

Per scoprire di più sui temi di Material in Compose, consulta le seguenti risorse:

App di esempio

Documenti

Riferimento API e codice sorgente

Video