I modificatori ti consentono di decorare o arricchire un componibile. I modificatori ti permettono di:
- Modificare le dimensioni, il layout, il comportamento e l'aspetto del componibile
- Aggiungere informazioni, ad esempio le etichette di accessibilità
- Elabora input utente
- Aggiungi interazioni di alto livello, come rendere un elemento cliccabile, scorribile, trascinabile o zoomabile.
I modificatori sono oggetti Kotlin standard. Crea un modificatore chiamando una delle funzioni di classe Modifier
:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
Puoi concatenare queste funzioni per comporle:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
Nel codice riportato sopra, puoi notare che le diverse funzioni di modifica sono utilizzate insieme.
padding
inserisce uno spazio intorno a un elemento.fillMaxWidth
consente al componibile di riempire la larghezza massima assegnata dal relativo elemento principale.
Come best practice, tutti gli elementi componibili accettano un parametro modifier
e lo passi al primo elemento figlio che emette UI.
In questo modo il tuo codice
è più riutilizzabile e il suo comportamento è più prevedibile e intuitivo. Per
ulteriori informazioni, consulta le linee guida dell'API Compose, Gli elementi accettano e rispettano un
parametro di modifica.
L'ordine dei modificatori è importante
L'ordine delle funzioni di modifica è significativo. Poiché ogni funzione apporta modifiche al Modifier
restituito dalla funzione precedente, la sequenza influisce sul risultato finale. Vediamo un esempio:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
Nel codice sopra l'intera area è cliccabile, inclusa la spaziatura interna, perché il modificatore padding
è stato applicato dopo il modificatore clickable
. Se l'ordine dei modificatori viene invertito, lo spazio aggiunto da padding
non reagisce all'input dell'utente:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
Modificatori integrati
Jetpack Compose fornisce un elenco di modificatori integrati per aiutarti a decorare o potenziare un componibile. Ecco alcuni comuni modificatori che utilizzerai per regolare i tuoi layout.
padding
e size
Per impostazione predefinita, i layout forniti in Compose aggregano i dati secondari. Tuttavia, puoi impostare una dimensione utilizzando il modificatore size
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
Tieni presente che le dimensioni specificate potrebbero non essere rispettate se non soddisfano i vincoli derivanti dall'elemento principale del layout. Se richiedi di fissare la dimensione componibile indipendentemente dai vincoli in entrata, utilizza il modificatore requiredSize
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
In questo esempio, anche con l'elemento height
principale impostato su 100.dp
, l'altezza di Image
sarà 150.dp
, poiché il modificatore requiredSize
ha la precedenza.
Se vuoi che un layout secondario riempia tutta l'altezza disponibile consentita dall'elemento principale, aggiungi il modificatore fillMaxHeight
(Scrittura fornisce anche fillMaxSize
e fillMaxWidth
):
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
Per aggiungere una spaziatura interna attorno a un elemento, imposta un modificatore padding
.
Se vuoi aggiungere una spaziatura interna sopra una base di riferimento del testo in modo da raggiungere una distanza specifica dalla parte superiore del layout alla base, utilizza il modificatore paddingFromBaseline
:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
Offset
Per posizionare un layout rispetto alla sua posizione originale, aggiungi il modificatore offset
e imposta l'offset sugli assi x e y.
Gli offset possono essere sia positivi che non positivi. La differenza tra padding
e offset
è che l'aggiunta di un offset
a un componibile non ne modifica le misure:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
Il modificatore offset
viene applicato orizzontalmente in base alla direzione del layout.
In un contesto da sinistra a destra, un valore offset
positivo sposta l'elemento a destra, mentre in un contesto da destra a sinistra sposta l'elemento a sinistra.
Se devi impostare un offset senza considerare la direzione del layout, vedi il modificatore di absoluteOffset
, in cui un valore di offset positivo sposta sempre l'elemento a destra.
Il modificatore offset
fornisce due sovraccarichi: offset
che prende gli
offset come parametri e offset
che accetta una lambda.
Per informazioni più dettagliate su quando utilizzarli e su come ottimizzare le prestazioni, leggi la sezione Prestazioni di Compose - Rimanda letture il più a lungo possibile.
Sicurezza dell'ambito in Compose
In Compose esistono modificatori che possono essere utilizzati solo se applicati a elementi secondari di determinati componibili. Compose applica questa impostazione mediante ambiti personalizzati.
Ad esempio, se vuoi impostare un asset secondario delle dimensioni dell'elemento principale Box
senza
influire sulla dimensione Box
, utilizza il
modificatore
matchParentSize
. matchParentSize
è disponibile solo in
BoxScope
.
Di conseguenza, può essere utilizzata solo su un figlio all'interno di un elemento padre Box
.
La sicurezza dell'ambito ti impedisce di aggiungere modificatori che non funzionerebbero in altri componibili e ambiti e ti fa risparmiare tempo per prove ed errori.
I modificatori con ambito informano l'elemento padre di alcune informazioni che quest'ultimo deve conoscere sull'elemento figlio. Questi sono anche comunemente indicati come modificatori dei dati principali. I loro componenti interni sono diversi dai modificatori per uso generico, ma dal punto di vista dell'utilizzo, queste differenze non sono importanti.
matchParentSize
in Box
Come accennato sopra, se vuoi che un layout secondario abbia le stesse dimensioni di un layout principale Box
senza influire sulle dimensioni Box
, utilizza il modificatore matchParentSize
.
Tieni presente che matchParentSize
è disponibile solo in un ambito Box
, il che significa che
si applica solo agli elementi secondari diretti di elementi componibili Box
.
Nell'esempio riportato di seguito, l'elemento secondario Spacer
prende le dimensioni dal relativo elemento secondario Box
,
che a sua volta prende le dimensioni dall'elemento secondario più grande,
ArtistCard
in questo caso.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Se venisse utilizzato fillMaxSize
al posto di matchParentSize
, Spacer
occuperebbe tutto lo spazio disponibile consentito per l'elemento principale, causando a sua volta l'espansione e l'esaurimento dello spazio disponibile.
weight
a Row
e Column
Come hai visto nella sezione precedente su Spaziatura interna e dimensioni, per impostazione predefinita una dimensione componibile viene definita dai contenuti a cui fa riferimento. Puoi impostare una dimensione componibile in modo che sia flessibile all'interno dell'elemento padre utilizzando il modificatore weight
, disponibile solo in RowScope
e ColumnScope
.
Prendiamo un elemento Row
che contiene due elementi componibili Box
.
La prima casella riceve il doppio del weight
del secondo, quindi viene doppiata della larghezza. Poiché Row
ha una larghezza di 210.dp
, la prima Box
è larga 140.dp
e la seconda 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
Estrazione e riutilizzo dei modificatori
Più modificatori possono essere concatenati per
arredare o arricchire un componibile. Questa catena viene creata tramite l'interfaccia Modifier
, che rappresenta un elenco ordinato e immutabile di un singolo elemento Modifier.Elements
.
Ogni Modifier.Element
rappresenta un comportamento individuale, ad esempio i comportamenti relativi a layout, disegno e grafica, tutti i comportamenti relativi a gesti, elementi di interesse e semantica, nonché eventi di input del dispositivo. L'ordinamento è importante: gli elementi modificatori
aggiunti per primi saranno applicati per primi.
A volte può essere utile riutilizzare le stesse istanze della catena di modificatori in più elementi componibili, estraendole in variabili e spostandole in ambiti più elevati. Può migliorare la leggibilità del codice o contribuire a migliorare le prestazioni della tua app per diversi motivi:
- La riallocazione dei modificatori non verrà ripetuta in caso di ricomposizione per gli elementi componibili che li utilizzano
- Le catene di modificatori potrebbero essere molto lunghe e complesse, quindi il riutilizzo della stessa istanza di una catena può ridurre il carico di lavoro richiesto dal runtime di Compose per il confronto
- Questa estrazione favorisce la pulizia, la coerenza e la manutebilità del codice in tutto il codebase
Best practice per il riutilizzo dei modificatori
Crea le tue catene Modifier
ed estraile per riutilizzarle su più componenti componibili. Non è assolutamente consentito salvare un modificatore, dato
che si tratta di oggetti simili ai dati:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Estrazione e riutilizzo dei modificatori in caso di cambiamenti frequenti dello stato
Quando osservi il cambiamento frequente degli stati all'interno di elementi componibili, come gli stati di un'animazione o scrollState
, è possibile che vengano eseguite una quantità significativa di ricomposizioni. In questo caso, i modificatori verranno assegnati a ogni ricomposizione
e potenzialmente per ogni frame:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
Puoi invece creare, estrarre e riutilizzare la stessa istanza del modificatore e passarla al componibile in questo modo:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
Estrazione e riutilizzo dei modificatori senza ambito
I modificatori possono limitare l'ambito o limitare l'ambito a un componibile specifico. Nel caso dei modificatori senza ambito, puoi estrarli facilmente al di fuori di qualsiasi componibile come semplice variabili:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Ciò può essere particolarmente utile se combinato con i layout lenti. Nella maggior parte dei casi, tutti gli elementi, potenzialmente significativi, avranno gli stessi modificatori:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
Estrazione e riutilizzo dei modificatori basati sull'ambito
Quando hai a che fare con modificatori che hanno come ambito determinati componibili, puoi estrarli al livello più alto possibile e riutilizzarli dove appropriato:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
Devi passare solo i modificatori con ambito estratti agli elementi secondari diretti con lo stesso ambito. Per ulteriori riferimenti sul motivo per cui è importante, consulta la sezione Sicurezza dell'ambito in Compose:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
Ulteriore concatenazione dei modificatori estratti
Puoi concatenare o aggiungere ulteriormente le catene di modificatori estratte chiamando la funzione .then()
:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
Tieni solo presente che l'ordine dei modificatori è importante.
Scopri di più
Forniamo un elenco completo dei modificatori, con i relativi parametri e ambiti.
Per ulteriore pratica sull'utilizzo dei modificatori, puoi anche consultare la pagina Layout di base nel codelab in Compose o consultare la pagina Repository Ora in Android.
Per saperne di più sui modificatori personalizzati e su come crearli, consulta la documentazione su Layout personalizzati - Utilizzo del modificatore di layout.
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Nozioni di base sul layout di scrittura
- Azioni dell'editor {:#editor-actions}
- Layout personalizzati {:#custom-layouts }