Material Design 3 in Compose

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

Di seguito dimostriamo l'implementazione di Material Design 3 utilizzando l'app di esempio Rispondi come esempio. L'esempio di Risposta si basa interamente su Material Design 3.

Rispondi all'app di esempio utilizzando Material Design 3
Figura 1. Rispondi all'app di esempio utilizzando Material Design 3

Dipendenza

Per iniziare a utilizzare Material 3 nell'app Compose, aggiungi la dipendenza Compose Material 3 ai tuoi file build.gradle:

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

Dopo aver aggiunto la dipendenza, puoi iniziare ad aggiungere sistemi di Material Design, inclusi colori, tipografia e forma, alle tue app.

API sperimentali

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

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

Temi del materiale

Un tema M3 contiene i seguenti sottosistemi: combinazione di colori, tipografia e forme. Quando personalizzi questi valori, le modifiche vengono applicate automaticamente nei 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 l'oggetto componibile MaterialTheme M3:

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

Per assegnare 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. Ciascuno di questi colori fa riferimento a una tavolozza di 13 tonalità, utilizzate dai componenti di Material 3. Ad esempio, questa è la combinazione di colori per il tema chiaro per Rispondi:

Combinazione di colori della spia dell'app di esempio della risposta
Figura 3. Schema di colori della spia dell'app di esempio della risposta

Scopri di più sui ruoli colore e combinazione di colori.

Genera combinazioni di colori

Anche se puoi creare manualmente un ColorScheme personalizzato, spesso è più facile generarne uno utilizzando i colori di origine del tuo brand. Lo strumento Generatore di temi Material ti consente di farlo e, se vuoi, di esportare il codice dei temi 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 chiari e scuri, utilizza isSystemInDarkTheme(). In base all'impostazione di sistema, definisci la combinazione di colori da utilizzare: chiaro o scuro.

Palette di colori dinamiche

Il colore dinamico è la parte chiave di Material You, in cui un algoritmo ricava i 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.

Rispondi con temi dinamici dell'app di esempio dallo sfondo (a sinistra) e da quelli predefiniti (a destra)
Figura 4. Rispondi con temi dinamici dell'app di esempio dallo sfondo (a sinistra) e da quelli predefiniti (a destra)

Il colore dinamico è disponibile su Android 12 e versioni successive. Se è disponibile un colore dinamico, puoi impostare un ColorScheme dinamico. In caso contrario, torna a usare un'opzione ColorScheme chiara o scura personalizzata.

ColorScheme offre funzioni di builder per creare una combinazione di colori dinamica chiara o scuro:

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

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

Ogni ruolo relativo al colore può essere utilizzato in una varietà di luoghi a seconda dello stato, dell'evidenza e dell'enfasi del componente.

  • Il principale è il colore di base, utilizzato per componenti principali come pulsanti in evidenza, stati attivi e tonalità delle superfici in evidenza.
  • Il colore della chiave secondaria viene utilizzato per i componenti meno visibili nell'interfaccia utente, ad esempio i chip di filtro, e espande le opportunità di espressione del colore.
  • Il colore della chiave terziaria viene utilizzato per ricavare i ruoli di accenti in contrasto che possono essere utilizzati per bilanciare i colori primari e secondari o per attirare maggiore attenzione a un elemento.

Il design dell'app di esempio Rispondi utilizza il colore on-primary-container sopra il container principale per enfatizzare l'elemento selezionato.

Contenitore principale e campi di testo con colore nel contenitore principale.
Figura 5. Contenitore principale e campi di testo con colore nel contenitore principale.

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,
    )
}

Nel riquadro di navigazione delle risposte puoi vedere come vengono utilizzati i colori dei contenitori secondari e terziari per creare enfasi e accenti.

Combinazione di contenitore terziario e contenitore terzo per il pulsante di azione mobile.
Figura 6. Combinazione di contenitore terziario e contenitore terzo per il pulsante di azione mobile.

Tipografia

Material Design 3 definisce una scala dei tipi, inclusi gli stili di testo adattati da Material Design 2. La denominazione e il raggruppamento sono stati semplificati in: display, titolo, titolo, corpo ed etichetta con ciascuno di questi formati: grandi, medi e piccoli.

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 tipografia

Compose fornisce la classe M3 Typography, insieme alle classi TextStyle e font-related esistenti, per modellare la scala di tipo Material 3. Il costruttore Typography offre valori predefiniti per ogni stile, così puoi 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 medio per diversi utilizzi tipografici.
Figura 8. Corpo grande, corpo di medie dimensioni ed etichetta media a seconda dell'uso tipografico.

È probabile che per il tuo prodotto non siano necessari tutti i 15 stili predefiniti della scala dei tipi di 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 delle proprietà TextStyle e 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 all'elemento MaterialTheme M3:

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

Utilizzare gli stili di testo

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

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

Scopri di più sulle linee guida di Material su come applicare la tipologia.

Forme

Le superfici dei materiali possono essere mostrate in diverse forme. Le forme indirizzano l'attenzione, identificano i componenti, comunicano lo stato ed esprimono il brand.

La scala della forma definisce lo stile degli angoli del contenitore, offrendo un'ampia gamma di arrotondamenti da quadrato a completamente circolare.

Definisci le forme

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

Esistono forme diverse:

  • Extra small
  • Piccolo
  • Medie
  • Large
  • Extra large

Per impostazione predefinita, ogni forma ha un valore predefinito, ma puoi 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 tuo Shapes, puoi passarlo all'MaterialTheme M3:

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

Utilizzare le forme

Puoi personalizzare la scala della forma per tutti i componenti in MaterialTheme o eseguire questa operazione per i singoli componenti.

Applica forma media e grande con valori predefiniti:

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

Forma media per Scheda e Forma grande per il pulsante di azione Floating nell'app di esempio Rispondi.
Figura 9. Forma media per la scheda e forma grande per il pulsante di azione mobile nell'app di esempio Rispondi

Ci sono altre due forme, RectangleShape e CircleShape, che fanno parte di Compose. La forma rettangolare è senza raggio del bordo e la forma del cerchio mostra i bordi cerchi completi:

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

Gli esempi riportati di seguito mostrano alcuni dei componenti a cui sono applicati valori di forma predefiniti:

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

Scopri di più sulle linee guida sui materiali per l'applicazione della forma.

Corsivo

L'enfasi in M3 viene fornita utilizzando variazioni di colore e le sue combinazioni di colori. In M3, esistono due modi per dare enfasi all'interfaccia utente:

  • Usando la superficie, la variante della superficie e lo sfondo insieme ai colori in superficie e sulle varianti della superficie del sistema di colori M3 espanso. Ad esempio, superficie può essere utilizzata con on-surface-variante e superficie-variante può essere usato con on-surface per fornire diversi livelli di enfasi.
Utilizzo di combinazioni di colori neutri per mettere in risalto il testo.
Figura 11. Usare combinazioni di colori neutri per mettere in risalto il testo.
  • Utilizzare spessori diversi per il testo. Sopra, hai visto che puoi specificare ponderazioni personalizzate per la scala dei tipi.

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

Altitudine

Il materiale 3 rappresenta l'elevazione utilizzando principalmente sovrapposizioni di colori tonali. Si tratta di un nuovo modo per distinguere i container e le superfici l'uno dall'altro: l'aumento dell'elevazione tonale comporta un tono più evidente, oltre alle ombre.

Elevazione tonale con elevazione delle ombre
Figura 12. Altitudine tonale con elevazione delle ombreE

Anche gli overlay elevazione nei temi scuri sono stati modificati in overlay con colori tonali in Material 3. Il colore dell'overlay proviene dall'area del colore principale.

Altitudine delle ombre e elevazione tonale in Material Design 3
Figura 13. Altitudine delle ombre e elevazione tonale in Material Design 3

Surface M3, il supporto componibile dietro la maggior parte dei componenti M3, include il supporto per l'elevazione dei toni e delle ombre:

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

Componenti del materiale

Material Design include un ampio set di componenti Material (ad esempio pulsanti, chip, schede e barra di navigazione), che già seguono la funzionalità Material Design e ti consentono di creare bellissime app di Material Design. Puoi iniziare a usare componenti con proprietà predefinite fin da subito.

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

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

Enfasi pulsante da FAB, pulsante Principale verso il basso fino a Testo
Figura 14. Pulsante Enfasi sul pulsante da FAB, Principale verso il basso fino a Testo
  • Un pulsante di azione mobile esteso per l'azione di enfasi più elevata:

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 di enfasi elevata:

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

  • Un pulsante di testo per un'azione di enfasi ridotta:

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

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

Material fornisce inoltre diversi componenti di navigazione che consentono di implementare la navigazione, a seconda delle dimensioni dello schermo e dello stato.

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 è utilizzato per tablet o telefoni di piccole e medie dimensioni in modalità Orizzontale. Offre un'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 delle risposte della barra di navigazione inferiore(sinistra) e della barra di navigazione(destra)
Figura 15. Vetrina delle risposte di BottomNavigationBar (sinistra) e NavigationRail (destra)

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

NavigationDrawer è utilizzato per tablet di medie e grandi dimensioni in cui hai spazio sufficiente per mostrare i dettagli. Puoi utilizzare sia PermanentNavigationDrawer che ModalNavigationDrawer insieme a NavigationRail.

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

Dimostrazione delle risposte a scomparsa 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 adattivo di Compose.

Personalizzare i temi di un componente

La versione M3 favorisce la personalizzazione e la flessibilità. A tutti i componenti sono applicati colori predefiniti, ma espongono API flessibili per personalizzarne i colori se necessario.

La maggior parte dei componenti, come schede e pulsanti, fornisce un oggetto predefinito che espone le interfacce di colore e elevazione che può essere modificato 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 derivano dal nuovo stile visivo e dalla nuova UI di sistema su Android 12 e versioni successive. Due aree chiave in cui si verificano le modifiche sono l'ondulazione e lo scorrimento orizzontale. Per implementare queste modifiche non è necessario alcun intervento aggiuntivo.

Onde

Ripple ora utilizza una leggera scintilla per illuminare le superfici quando viene premuto. Compose Material Ripple utilizza la piattaforma RippleDrawable su Android, per cui sparkle Ripple è disponibile su Android 12 e versioni successive per tutti i componenti di Material.

Ripple in M2 contro M3
Figura 17. Onde in M2 rispetto a M3

Scorrimento orizzontale

Lo scorrimento orizzontale ora utilizza un effetto allungato sul bordo dei container a scorrimento. L'opzione allunga l'overscroll è attiva per impostazione predefinita nei contenitori componibili a scorrimento, ad esempio LazyColumn, LazyRow e LazyVerticalGrid, in Compose Foundation 1.1.0 e versioni successive, indipendentemente dal livello API.

Scorrimento orizzontale con l'effetto Estendi sui bordi del container
Figura 18. Scorri il dito sopra usando l'effetto Estendi sui bordi del container

Accessibilità

Gli standard di accessibilità integrati nei componenti Material sono progettati per fornire le basi per un design di prodotto inclusivo. Comprendere l'accessibilità del tuo prodotto può migliorare l'usabilità per tutti gli utenti, inclusi quelli ipovedenti, ciechi, ipoudenti, cognitivi, 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 di colore. Il sistema di tavolozze tonali è fondamentale per rendere accessibile per impostazione predefinita qualsiasi combinazione di colori.

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

App di esempio per la risposta: pallet tonali primari, secondari e terziari (dall'alto verso il basso)
Figura 19. App di esempio per la risposta: tavolozze dei toni primari, secondari e terziari (dall'alto verso il basso)

Tutti i componenti Materiali e i temi dinamici utilizzano già i ruoli colore sopra riportati da un insieme di tavolozze dei toni, selezionate per soddisfare i requisiti di accessibilità. Tuttavia, se stai personalizzando i componenti, assicurati di utilizzare i ruoli colore appropriati ed evita di non corrispondere.

Utilizza il tipo on-primary sopra il contenitore principale e nel contenitore principale sopra il container principale, e lo stesso per altri colori intensi e neutri per fornire un contrasto accessibile all'utente.

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

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

Ad esempio, nel modello M3 è possibile assegnare valori diversi a seconda del contesto del dispositivo, ad esempio un telefono o un tablet.

Schermi grandi

Material fornisce indicazioni su layout adattivi e pieghevoli per rendere accessibili le app e migliorare l'ergonomia degli utenti con dispositivi di grandi dimensioni.

Material fornisce diversi tipi di navigazione per aiutarti a offrire una migliore esperienza utente per i dispositivi di grandi dimensioni.

Scopri di più sulle linee guida per lo schermo grande di Android e consulta il nostro esempio di risposta per un design adattivo e accessibile.

Scopri di più

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

App di esempio

Documenti

Riferimento API e codice sorgente

Video