I modificatori ti consentono di decorare o aumentare un elemento componibile. I modificatori ti consentono di fare cose come:
- Modificare le dimensioni, il layout, il comportamento e l'aspetto del componente componibile
- Aggiungere informazioni, ad esempio etichette di accessibilità
- Elaborare l'input dell'utente
- Aggiungi interazioni di alto livello, ad esempio rendi un elemento selezionabile, scorrevole, trascinabile o ingrandibile
I modificatori sono oggetti Kotlin standard. Crea un modificatore chiamando una delle funzioni della 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, nota le diverse funzioni di modifica utilizzate insieme.
padding
aggiunge spazio intorno a un elemento.fillMaxWidth
fa in modo che il componibile riempia la larghezza massima che gli viene assegnata dal relativo elemento padre.
È una best practice che tutti i tuoi componenti componibili accettino un parametro modifier
e passino questo modificatore al primo elemento secondario che emette l'interfaccia utente.
In questo modo, il codice è più riutilizzabile e il suo comportamento è più prevedibile e intuitivo. Per
maggiori informazioni, consulta le linee guida dell'API Compose, Gli elementi accettano e rispettano un
parametro Modifier.
L'ordine dei modificatori è importante
L'ordine delle funzioni modificatore è importante. Poiché ogni funzione apporta modifiche al valore 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 è selezionabile, incluso il padding circostante, 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 aumentare un composable. Ecco alcuni modificatori comuni che utilizzerai per regolare i layout.
padding
e size
Per impostazione predefinita, i layout forniti in Compose eseguono il wrapping dei relativi elementi 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 del layout principale. Se vuoi che le dimensioni
componibili siano fisse 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 se l'elemento principale height
è 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 dal
genitore, aggiungi il modificatore fillMaxHeight
(Compose 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 intorno a un elemento, imposta un modificatore padding
.
Se vuoi aggiungere un riempimento sopra una linea di base del testo in modo da ottenere una
distanza specifica dalla parte superiore del layout alla linea di 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 negli assi x e y.
Gli offset possono essere positivi e non positivi. La differenza tra
padding
e offset
è che l'aggiunta di un offset
a un elemento componibile non
ne modifica le misurazioni:
@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 positivo di offset
sposta l'elemento a destra, mentre in un contesto da destra a sinistra, lo sposta a sinistra.
Se devi impostare un offset senza considerare la direzione del layout, consulta il modificatore
absoluteOffset
, in cui un valore di offset positivo sposta sempre l'elemento a
destra.
Il modificatore offset
fornisce due overload: offset
che accetta gli offset come parametri e offset
che accetta una lambda.
Per informazioni più dettagliate su quando utilizzare ciascuna di queste opzioni e su come ottimizzare
il rendimento, leggi la sezione
Composizione delle prestazioni: posticipa le letture il più a lungo possibile.
Sicurezza degli ambiti in Compose
In Compose, esistono modificatori che possono essere utilizzati solo se applicati ai figli di determinati composable. Compose lo applica tramite ambiti personalizzati.
Ad esempio, se vuoi rendere un elemento figlio grande quanto l'elemento padre Box
senza
influire sulle dimensioni di Box
, utilizza il modificatore
matchParentSize
. matchParentSize
è disponibile solo in
BoxScope
.
Pertanto, può essere utilizzato solo su un bambino all'interno di un genitore Box
.
La sicurezza dell'ambito ti impedisce di aggiungere modificatori che non funzionerebbero in altri composizioni e ambiti e ti fa risparmiare tempo evitando tentativi ed errori.
I modificatori con ambito comunicano al genitore alcune informazioni che deve sapere sul figlio. Questi vengono anche comunemente chiamati modificatori dei dati principali. Il loro funzionamento interno è diverso dai modificatori generici, ma dal punto di vista dell'utilizzo, queste differenze non contano.
matchParentSize
in Box
Come accennato in precedenza, se vuoi che un layout secondario abbia le stesse dimensioni di un layout principale
Box
senza influire sulle dimensioni di Box
, utilizza il modificatore matchParentSize
.
Tieni presente che matchParentSize
è disponibile solo all'interno di un ambito Box
, il che significa che
si applica solo agli elementi secondari diretti dei componenti componibili Box
.
Nell'esempio seguente, l'elemento secondario Spacer
prende le dimensioni dall'elemento principale Box
,
che a sua volta prende le dimensioni dagli elementi secondari più grandi,
ArtistCard
in questo caso.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Se fosse stato utilizzato fillMaxSize
anziché matchParentSize
, Spacer
avrebbe occupato
tutto lo spazio disponibile consentito al genitore, il quale si sarebbe
espanso e avrebbe riempito tutto lo spazio disponibile.
weight
in Row
e Column
Come hai visto nella sezione precedente su Spaziatura interna e
dimensioni, per impostazione predefinita, le dimensioni di un elemento componibile sono definite dal
contenuto che racchiude. Puoi impostare le dimensioni di un componibile in modo che siano flessibili all'interno del relativo
elemento padre utilizzando il modificatore weight
disponibile solo in RowScope
e
ColumnScope
.
Prendiamo un Row
che contiene due composable Box
.
La prima casella ha una weight
doppia rispetto alla seconda, quindi ha una larghezza doppia. Poiché Row
è largo 210.dp
, il primo Box
è largo 140.dp
e
il secondo è 70.dp
:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
Estrazione e riutilizzo dei modificatori
È possibile concatenare più modificatori per decorare o
aumentare un elemento componibile. Questa catena viene creata tramite l'interfaccia Modifier
, che rappresenta un elenco ordinato e immutabile di singoli Modifier.Elements
.
Ogni Modifier.Element
rappresenta un comportamento individuale, come layout, disegno e grafica, tutti relativi ai gesti, ai comportamenti di messa a fuoco e semantici, nonché agli eventi di input del dispositivo. L'ordine è importante: gli elementi modificatori aggiunti per primi verranno applicati per primi.
A volte può essere utile riutilizzare le stesse istanze della catena di modificatori in più composable, estraendole in variabili e spostandole in ambiti più elevati. Può migliorare la leggibilità del codice o contribuire a migliorare le prestazioni dell'app per alcuni motivi:
- La riassegnazione dei modificatori non verrà ripetuta quando si verifica la ricomposizione per i composable che li utilizzano
- Le catene di modificatori potrebbero essere molto lunghe e complesse, quindi il riutilizzo della stessa istanza di una catena può alleviare il carico di lavoro che deve svolgere il runtime di Compose quando le confronta.
- Questa estrazione promuove la pulizia, la coerenza e la manutenibilità del codice in tutto il codebase
Best practice per il riutilizzo dei modificatori
Crea le tue catene Modifier
ed estraile per riutilizzarle in più componenti componibili. È perfettamente accettabile salvare solo un modificatore, in quanto
si tratta di oggetti simili a dati:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Estrazione e riutilizzo dei modificatori quando si osserva uno stato che cambia frequentemente
Quando si osservano stati che cambiano frequentemente all'interno dei composable, come gli stati di animazione o scrollState
, possono essere eseguite un numero significativo di ricomposizioni. In questo caso, i modificatori verranno allocati 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 ) }
In alternativa, puoi creare, estrarre e riutilizzare la stessa istanza del modificatore e passarla al componibile nel seguente 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 essere senza ambito o con ambito per un componente componibile specifico. Nel caso di modificatori senza ambito, puoi estrarli facilmente al di fuori di qualsiasi elemento componibile come semplici 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 pigri. Nella maggior parte dei casi, vorrai che tutti i tuoi articoli, potenzialmente in quantità significativa, abbiano esattamente 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 con ambito
Quando gestisci modificatori con ambito limitato a determinati componenti combinabili, puoi estrarli al livello più alto possibile e riutilizzarli dove opportuno:
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 trasmettere i modificatori estratti e con ambito solo ai figli diretti con lo stesso ambito. Per ulteriori informazioni sull'importanza di questo aspetto, consulta la sezione Sicurezza dell'ambito in Componi:
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 presente che l'ordine dei modificatori è importante.
Scopri di più
Forniamo un elenco completo dei modificatori, con i relativi parametri e ambiti.
Per esercitarti ulteriormente su come utilizzare i modificatori, puoi anche consultare il codelab sui layout di base in Compose o fare riferimento al repository Now in Android.
Per saperne di più sui modificatori personalizzati e su come crearli, consulta la documentazione su Layout personalizzati - Utilizzo del modificatore di layout.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Nozioni di base sul layout di composizione
- Azioni dell'editor {:#editor-actions}
- Layout personalizzati {:#custom-layouts }