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) si basano su Material Design, che è un modo sistematico di personalizzare Material Design in modo che rispecchi meglio il brand del tuo prodotto. Un tema Materiale contiene gli attributi colore, tipografia e forma. Quando personalizzi questi attributi, le modifiche vengono applicate automaticamente nei componenti che utilizzi per creare la tua app.
Jetpack Compose implementa questi concetti con il componente componibile MaterialTheme
:
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Configura i parametri che passi a MaterialTheme
per tematizzare l'applicazione.
Figura 1. Il primo screenshot mostra un'app che non configura MaterialTheme
, quindi utilizza lo stile predefinito. Il secondo screenshot mostra un'app che trasmette i parametri a MaterialTheme
per personalizzare lo stile.
Colore
I colori sono modellati in Compose con la classe Color
, una semplice
classe di conservazione dei dati.
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
Sebbene tu possa organizzarli come preferisci (come costanti di primo livello, all'interno di un singolo singolo o definito in linea), ti consigliamo vivamente di specificare i colori nel tema e di recuperarli da lì. Questo approccio consente di supportare facilmente tema scuro e temi nidificati.
Figura 2. Il sistema di colori Materiale.
Compose fornisce la classe Colors
per modellare il
Sistema di colori Material. Colors
fornisce le funzioni del builder per creare set di colori chiari o scuri:
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
Una volta definito il Colors
, puoi passarlo a un MaterialTheme
:
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Utilizzo dei colori del tema
Puoi recuperare il Colors
fornito al componibile MaterialTheme
utilizzando MaterialTheme.colors
.
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
Colore superficie e contenuto
Molti componenti accettano una coppia di colori e colori dei contenuti:
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Questo consente non solo di impostare il colore di un componibile, ma anche di fornire
un colore predefinito per i contenuti,ovvero i componibili al suo interno. Molti
componibili utilizzano questo colore dei contenuti per impostazione predefinita. Ad esempio, Text
basa il proprio colore sul colore dei contenuti dell'elemento principale, mentre Icon
lo utilizza per impostare il colore.
Figura 3. L'impostazione di colori di sfondo diversi consente di produrre testo e icone di colori diversi.
Il metodo contentColorFor()
recupera il colore "on" appropriato per tutti i colori del tema. Ad esempio, se imposti un colore di sfondo primary
su Surface
, la funzione viene utilizzata per impostare onPrimary
come colore del contenuto. Se imposti un colore di sfondo non correlato al tema, devi specificare anche un colore per i contenuti appropriato. Utilizza LocalContentColor
per recuperare il colore dei contenuti preferito per lo sfondo corrente, in una determinata posizione nella gerarchia.
Contenuti alpha
Spesso è necessario specificare un livello di enfasi diverso per i contenuti per comunicare l'importanza e fornire una gerarchia visiva. I suggerimenti sulla leggibilità del testo di Material Design consigliano di utilizzare diversi livelli di opacità per trasmettere livelli di importanza differenti.
Jetpack Compose implementa questa operazione tramite LocalContentAlpha
.
Puoi specificare una versione alpha dei contenuti per una gerarchia fornendo un valore per questa CompositionLocal
.
I componibili nidificati possono utilizzare questo valore per applicare il trattamento alfa ai propri contenuti.
Ad esempio, Text
e Icon
per impostazione predefinita utilizzano la combinazione di LocalContentColor
con aggiustamento per l'uso di LocalContentAlpha
. Il materiale specifica alcuni valori alfa standard (high
, medium
,
disabled
) modellati dall'oggetto ContentAlpha
.
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Per saperne di più su CompositionLocal
, consulta la guida sui dati con ambito locale con
la guida ComposeLocal.
Figura 4. Applicare diversi livelli di enfasi al testo
per comunicare visivamente la gerarchia delle informazioni. La prima riga di testo è il titolo e contiene le informazioni più importanti, pertanto utilizza ContentAlpha.high
. La seconda riga contiene metadati meno importanti e quindi utilizza ContentAlpha.medium
.
Tema scuro
In Compose, implementerai temi chiari e scuri fornendo diversi set di
Colors
all'elemento componibile MaterialTheme
:
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
In questo esempio, MaterialTheme
è racchiuso nella propria funzione componibile,
che accetta un parametro che specifica se utilizzare o meno un tema scuro. In questo caso, la funzione recupera il valore predefinito di darkTheme
eseguendo una query sull'impostazione del tema del dispositivo.
Puoi utilizzare questo codice per controllare se gli attuali Colors
sono chiari o scuri:
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Overlay altitudine
In Material, le superfici in temi scuri ad altitudini più elevate ricevono overlay di elevazione, che illuminano lo sfondo. Più alta è l'elevazione della superficie (più vicina a una sorgente di luce implicita), più la superficie diventa più leggera.
Questi overlay vengono applicati automaticamente dall'elemento componibile Surface
quando si utilizzano colori scuri e per qualsiasi altro materiale componibile che utilizza una superficie:
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
Figura 5. Le schede e la barra di navigazione in basso utilizzano entrambe il colore surface
come sfondo. Poiché le schede e la barra di navigazione in basso si trovano a livelli di altitudine diversi rispetto allo sfondo, hanno colori leggermente diversi: le schede sono più chiare dello sfondo e la navigazione in basso è più chiara delle schede.
Per gli scenari personalizzati che non prevedono un Surface
, utilizza
LocalElevationOverlay
,
un CompositionLocal
contenente il
ElevationOverlay
utilizzato dai
Surface
componenti:
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Per disattivare gli overlay di elevazione, fornisci null
nel punto desiderato di una gerarchia componibile:
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Accenti di colore limitati
Material consiglia di applicare accenti di colore limitati per i temi scuri preferendo l'uso del colore surface
rispetto al colore primary
nella maggior parte dei casi. I materiali componibili come TopAppBar
e BottomNavigation
implementano questo comportamento per impostazione predefinita.
Figura 6. Tema scuro in stile materiale con accenti cromatici limitati. La barra dell'app in alto utilizza il colore principale nel tema chiaro e il colore della superficie nel tema scuro.
Per gli scenari personalizzati, utilizza la proprietà dell'estensione primarySurface
:
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Tipografia
Material definisce un sistema di tipi, incoraggiandoti a utilizzare un numero ridotto di stili con nome semantico.
Figura 7. Il sistema Material Type.
Compose implementa il sistema dei tipi con le classi Typography
, TextStyle
e font-related. Il costruttore Typography
offre valori predefiniti per ogni stile, così puoi omettere quelli che non vuoi personalizzare:
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Se vuoi utilizzare lo stesso carattere, specifica defaultFontFamily parameter
e ometti fontFamily
di qualsiasi elemento TextStyle
:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Utilizzo degli stili di testo
TextStyle
è accessibile tramite MaterialTheme.typography
. Recupera i TextStyle
in questo modo:
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
Figura 8. Utilizza una selezione di caratteri tipografici e stili per esprimere il tuo brand.
Forma
Il materiale definisce un sistema di forme, che consente di definire le forme per componenti di grandi dimensioni, medie e piccole.
Figura 9. Il sistema di forme dei materiali.
Compose implementa il sistema di forme con la classe Shapes
, che consente di specificare un CornerBasedShape
per ogni categoria di dimensioni:
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
Molti componenti utilizzano queste forme per impostazione predefinita. Ad esempio,
Button
,
TextField
e
FloatingActionButton
il valore predefinito è Small,
AlertDialog
il valore predefinito è Medio e
ModalDrawer
il valore predefinito è Large. Per il mapping completo, consulta il
riferimento allo schema delle forme
per il mapping completo.
Utilizzo delle forme
Shape
è accessibile tramite MaterialTheme.shapes
. Recupera i Shape
con
un codice come questo:
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
Figura 10. Utilizza le forme per esprimere il brand o lo stato.
Stili predefiniti
Non esiste un concetto equivalente in Scrivi degli stili predefiniti di Android View. Puoi fornire una funzionalità simile creando le tue funzioni componibili di "sovraccarico" che aggregano i componenti Material. Ad esempio, per creare uno stile di pulsante, aggrega un pulsante nella tua funzione componibile, impostando direttamente i parametri che vuoi modificare ed esponendo gli altri come parametri all'elemento componibile contenitore.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Overlay di temi
Puoi ottenere l'equivalente degli
overlay dei temi delle visualizzazioni Android in Compose, nidificando gli
elementi componibili di MaterialTheme
. Poiché
MaterialTheme
imposta per impostazione predefinita colori, tipografia e forme in base al valore del tema corrente, se un tema imposta solo uno di questi parametri, gli altri parametri manterranno i valori predefiniti.
Inoltre, quando esegui la migrazione delle schermate basate sulle visualizzazioni a Compose, presta attenzione agli utilizzi dell'attributo android:theme
. È probabile che tu abbia bisogno di un nuovo
MaterialTheme
in quella parte della struttura ad albero dell'interfaccia utente di Compose.
Nell'esempio di gufo, la schermata dei dettagli utilizza PinkTheme
per la maggior parte della schermata, quindi BlueTheme
per la sezione correlata. Guarda screenshot e codice di seguito.
Figura 11. Temi nidificati nell'esempio del gufo.
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
Stati del componente
I componenti materiali con cui è possibile interagire (clic, pulsante e così via) possono trovarsi in stati visivi diversi. Gli stati includono attivato, disattivato, premuto e così via.
I componibili hanno spesso un parametro enabled
. Se il criterio viene impostato su false
, l'interazione non viene consentita e vengono modificate proprietà come colore ed elevazione per trasmettere visivamente lo stato del componente.
Figura 12. Pulsante con enabled = true
(sinistra) e enabled = false
(destra).
Nella maggior parte dei casi puoi utilizzare i valori predefiniti per valori come colore e elevazione. Per configurare valori utilizzati in stati diversi, sono disponibili classi e funzioni di convenienza. Vedi l'esempio di pulsante di seguito:
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
Figura 13. Pulsante con enabled = true
(sinistra) e enabled = false
(destra), con valori di colore e altitudine regolati.
Increspature
I componenti Material utilizzano le onde per indicare l'interazione con i componenti. Se
utilizzi MaterialTheme
nella gerarchia, un Ripple
verrà usato come
valore predefinitoIndication
all'interno di modificatori come
clickable
e
indication
.
Nella maggior parte dei casi puoi usare il valore predefinito Ripple
. Se vuoi configurarne l'aspetto, puoi utilizzare RippleTheme
per modificare proprietà come colore e alpha.
Puoi estendere RippleTheme
e utilizzare le funzioni di utilità
defaultRippleColor
e
defaultRippleAlpha
. Puoi quindi fornire il tuo tema a onde personalizzato nella gerarchia utilizzando LocalRippleTheme
:
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
Figura 14. Pulsanti con diversi valori dell'onda forniti tramite RippleTheme
.
Scopri di più
Per scoprire di più sui temi dei materiali in Compose, consulta le seguenti risorse aggiuntive.
Codelab
Video
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Sistemi di progettazione personalizzati in Compose
- Eseguire la migrazione da Material 2 a Material 3 in Compose
- Accessibilità in Compose