Material Design 3 in Compose

Jetpack Compose offre un'implementazione di Material Design 3, la prossima evoluzione di Material Design. Material 3 include temi, componenti e funzionalità di personalizzazione di Material You aggiornati, come i colori dinamici, ed è progettato per essere coerente con il nuovo stile visivo e la nuova UI di sistema su Android 12 e versioni successive.

Di seguito viene mostrata l'implementazione di Material Design 3 utilizzando come esempio l'app di esempio di risposta. L'esempio di risposta si basa interamente su Material Design 3.

App di esempio di risposta che utilizza Material Design 3
Figura 1. App di esempio di risposta 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 sistemi Material Design, tra cui colore, tipografia e forma, alle tue app.

API sperimentali

Alcune API M3 sono considerate sperimentali. In questi casi, devi attivare la funzionalità 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, typography e forme. Quando personalizzi questi valori, le modifiche vengono applicate automaticamente ai componenti M3 che utilizzi per creare l'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 composable M3 MaterialTheme:

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

Per applicare un tema ai contenuti dell'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 di cinque colori chiave. Ognuno di questi colori si riferisce a una tavolozza di 13 tonalità, utilizzata dai componenti di Material 3. Ad esempio, questa è la combinazione di colori per il tema chiaro di Rispondi:

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

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

Generare combinazioni di colori

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

  • Color.kt contiene i colori del tema con tutti i ruoli definiti sia per i colori del tema chiaro che per quelli scuri.

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 chiare e scure e per 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 è utilizzata come punto di partenza per generare combinazioni di colori chiari e scuri.

Temi dinamici dell'app di esempio di Rispondi dallo sfondo (a sinistra) e temi dell'app predefiniti (a destra)
Figura 4. Rispondi ai temi dinamici dell'app di esempio dallo sfondo (a sinistra) e dai 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, utilizza un ColorScheme chiaro o scuro personalizzato.

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

// 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 Material nella tua app tramite MaterialTheme.colorScheme:

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

Ogni ruolo del colore può essere utilizzato in diversi posti, a seconda dello stato, dell'evidenza e dell'enfasi del componente.

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

Il design dell'app di esempio di Risposta 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 il 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 delle risposte come vengono usati i colori secondari e terziari del contenitore per creare enfasi e accenti.

Combinazione di contenitore terziario e contenitore terziario per il pulsante di azione mobile.
Figura 6. Combinazione di container terziario e on-terziario-container per il pulsante di azione mobile.

Tipografia

Material Design 3 definisce una scala di tipo, inclusi gli stili di testo che sono stati adattati da Material Design 2. La denominazione e il raggruppamento sono stati semplificati in: display, titolo, titolo, testo e etichetta, con dimensioni grandi, medie e piccole per ciascuna.

Scala tipografica predefinita per Material Design 3
Figura 7. Scala tipografia predefinita per Material Design 3
M3 Dimensioni carattere/altezza riga predefinite
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 M3 Typography, insieme alle classi TextStyle e font-related esistenti, per modellare la scala del tipo 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, mezzo corpo e mezzo etichetta per diversi utilizzi tipografici.
Figura 8. Testo grande, testo 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 di tipo Material Design. In questo esempio, vengono scelte cinque dimensioni per un insieme ridotto, mentre il resto viene omesso.

Puoi personalizzare la tipografia modificando i valori predefiniti di TextStyle e le proprietà correlate 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 M3:

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

Utilizzare gli stili di testo

Puoi recuperare i caratteri tipografici forniti nell'M3 MaterialTheme componibile utilizzando MaterialTheme.typography:

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

Per saperne di più sulle linee guida di Material per l'applicazione della tipografia, consulta la pagina dedicata.

Forme

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

La scala delle forme definisce lo stile degli angoli del contenitore, offrendo una gamma di rotondità da quadrata a completamente circolare.

Definire le forme

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

Esistono forme di diverse dimensioni:

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

Per impostazione predefinita, ogni forma ha un valore predefinito, ma è possibile sostituirli:

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

Una volta definito il Shapes, puoi passarlo all'M3 MaterialTheme:

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

Utilizzare le forme

Puoi personalizzare la scala delle forme per tutti i componenti in MaterialTheme o per singolo componente.

Applica una forma di medie e grandi dimensioni con 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 pulsante di azione mobile nell'app di esempio Rispondi.
Figura 9. Forma media per la scheda e forma grande per il pulsante di azione popup nell'app di esempio Rispondi

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

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

I seguenti esempi mostrano alcuni dei componenti con valori di forma predefiniti applicati:

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

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

Corsivo

L'enfasi in M3 viene fornita utilizzando variazioni di colore e le relative combinazioni in tinta. In M3, esistono due modi per mettere in evidenza l'interfaccia utente:

  • Utilizzo dei colori delle varianti di superficie, delle varianti di superficie e dello sfondo insieme ai colori delle varianti in superficie e in superficie del sistema di colori M3 ampliato. Ad esempio, la proprietà surface può essere utilizzata con la proprietà on-surface-variant e la proprietà surface-variant può essere utilizzata con la proprietà on-surface per fornire diversi livelli di enfasi.
Utilizzare combinazioni di colori neutri per dare enfasi.
Figura 11. Utilizza combinazioni di colori neutri per dare enfasi.
  • Utilizzare spessori di carattere diversi per il testo. Sopra, hai visto che puoi fornire ponderazioni personalizzate alla nostra scala dei tipi per enfatizzare diversamente.

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

Altitudine

Il materiale 3 rappresenta l'elevazione principalmente utilizzando overlay di colori tonali. Si tratta di 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 con elevazione ombra
Figura 12. Elevazione tonale con illuminazione in ombraE

Anche le sovrapposizioni di elevazione nei temi scuri sono state sostituite da sovrapposizioni di colori tonali in Material 3. Il colore dell'overlay proviene dallo spazio del colore principale.

Elevazione delle ombre e Elevazione tonale in Material Design 3
Figura 13. Elevazione delle ombre rispetto all'elevazione tonale in Material Design 3

La superficie M3, il composable di supporto alla base della maggior parte dei componenti M3, include il supporto sia per l'elevazione tonale che per quella delle ombre:

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

Componenti di materiale

Material Design include un'ampia gamma di componenti Material (ad esempio pulsanti, chip, schede, barra di navigazione) che già seguono Material Theme e ti aiutano a creare bellissime app Material Design. Puoi iniziare a utilizzare subito i componenti con proprietà predefinite.

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 pulsante da FAB, pulsante Principale a Testo
Figura 14. Enfasi del pulsante da FAB, principale a pulsante di testo
  • Un pulsante di azione mobile esteso per l'azione di maggiore 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 con riempimento per un'azione di grande enfasi:

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

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

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

Scopri 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 appositamente 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 dimensioni e degli stati dello schermo.

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

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

NavigationRail viene utilizzato per i tablet di piccole e medie dimensioni o per gli smartphone 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 = { }
        )
    }
}

Mostra di risposte di BottomNavigationBar(a sinistra) e NavigationRail(a destra)
Figura 15. Rispondi a Showcase di BottomNavigationBar (sinistra) e NavigationRail (destra)

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

NavigationDrawer viene utilizzato per tablet di medie e grandi dimensioni in cui hai abbastanza spazio 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 = { }
        )
    }
}) {
}

Mostra di Reply del riquadro di navigazione permanente
Figura 16. Vetrina delle risposte 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 Material nel codelab Componi adattativo.

Personalizzare il tema di un componente

M3 incoraggia la personalizzazione e la flessibilità. A tutti i componenti vengono applicati colori predefinite, ma sono disponibili API flessibili per personalizzarli, se necessario.

La maggior parte dei componenti, come schede e pulsanti, fornisce un'interfaccia predefinita per l'esposizione del colore e dell'elevazione degli oggetti che può essere modificata 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
}

Scopri di più sulla personalizzazione di Material 3.

UI di sistema

Alcuni aspetti di Material You provengono dal nuovo stile visivo e dall'interfaccia utente di sistema su Android 12 e versioni successive. Due aree chiave in cui si verificano modifiche sono l'eco e lo scorrimento sopra l'immagine. Non sono necessarie ulteriori operazioni per implementare queste modifiche.

Onde

Ora l'effetto Ripple utilizza una scintilla sottile per illuminare le superfici quando viene premuto. Onda Materiale di Compose utilizza una piattaforma RippleDrawable sotto il cofano su Android, quindi l'effetto scintilla è disponibile su Android 12 e versioni successive per tutti i componenti Materiale.

Ripple in M2 e M3
Figura 17. Onde in M2 e M3

Scorrimento eccessivo

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

Scroll eccessivo con effetto di allungamento sul bordo del contenitore
Figura 18. Scroll eccessivo con effetto di allungamento sul bordo del contenitore

Accessibilità

Gli standard di accessibilità integrati nei componenti Material sono progettati per fornire le basi per una progettazione inclusiva del prodotto. Comprendere l'accessibilità del tuo prodotto può migliorare l'usabilità per tutti gli utenti, inclusi quelli con disabilità visive, cecità, disturbi uditivi, disturbi cognitivi, disturbi motori o disabilità situazionali (ad esempio un braccio rotto).

Accessibilità dei colori

Il colore dinamico è progettato per soddisfare gli standard di accessibilità per il contrasto dei colori. Il sistema di tavolozze di tonalità è 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 di Reply: palette di tonalità principali, secondarie e terziarie (dall'alto verso il basso)
Figura 19. App di esempio di Reply: tavolozze di tonalità principali, secondarie e terziarie (dall'alto verso il basso)

Tutti i componenti Material e i temi dinamici utilizzano già i ruoli di colore sopra indicati da un insieme di tavolozze di tonalità, selezionate per soddisfare i requisiti di accessibilità. Tuttavia, se stai personalizzando i componenti, assicurati di utilizzare i ruoli relativi ai colori appropriati ed evita di trovare corrispondenze errate.

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

L'utilizzo di un container terziario sopra quello principale offre all'utente un pulsante a basso contrasto:

// ✅ 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 scarso (a destra)
Figura 20. Contrasto sufficiente (a sinistra) e scarso (a destra)

Accessibilità della tipografia

La scala di tipo M3 aggiorna la rampa e i valori del tipo statico per offrire un framework semplificato ma dinamico di categorie di dimensioni scalabili su tutti i 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 su layout adattivi e pieghevoli per rendere le tue app accessibili e migliorare l'ergonomia degli utenti che tengono in mano dispositivi di grandi dimensioni.

Material fornisce diversi tipi di navigazione per aiutarti a offrire un'esperienza utente migliore per i dispositivi 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 adattabile e accessibile.

Scopri di più

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

App di esempio

Documenti

Riferimento API e codice sorgente

Video