I modificatori ti consentono di decorare o migliorare un componibile. I modificatori ti consentono di fare cose come:
- Modificare le dimensioni, il layout, il comportamento e l'aspetto del composable
- Aggiungi informazioni, ad esempio etichette di accessibilità
- Elabora l'input dell'utente
- Aggiungi interazioni di alto livello, ad esempio rendi un elemento cliccabile, scorrevole, trascinabile o zoomabile
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.
paddinginserisce uno spazio intorno a un elemento.fillMaxWidthfa sì che l'elemento componibile occupi la larghezza massima assegnata dall'elemento principale.
È una best practice fare in modo che tutti i composabili accettino un parametro modifier e passino questo modificatore al primo elemento secondario che genera l'UI.
In questo modo, il codice diventa più riutilizzabile e il suo comportamento più prevedibile e intuitivo. Per saperne di più, consulta le linee guida dell'API Compose, Gli elementi accettano e rispettano un parametro Modifier.
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 riportato sopra, l'intera area è cliccabile, 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 migliorare un componibile. Ecco alcuni modificatori comuni che utilizzerai per regolare i layout.
padding e size
Per impostazione predefinita, i layout forniti in Compose avvolgono i 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 provenienti dall'elemento principale del layout. Se hai bisogno che le dimensioni del composable 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 occupi tutta l'altezza disponibile consentita dal layout principale, 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 spaziatura interna intorno a un elemento, imposta un modificatore padding.
I parametri start e end di padding seguono la direzione del layout. Per aggiungere spaziatura interna al bordo sinistro o destro indipendentemente dalla direzione del layout, utilizza absolutePadding con i parametri left e right.
Se vuoi aggiungere spaziatura interna 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 nell'asse x e y.
Gli offset possono essere positivi o non positivi. La differenza tra
padding e offset è che l'aggiunta di un offset a un composable 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 in orizzontale 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, 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 funzione lambda.
Per informazioni più approfondite su quando utilizzare ciascuna di queste opzioni e su come ottimizzare le prestazioni, consulta la sezione Prestazioni di Compose - Rimanda le letture il più possibile.
Sicurezza dell'ambito in Compose
In Compose, esistono modificatori che possono essere utilizzati solo se applicati ai componenti secondari di determinati componibili. Compose applica questa regola tramite ambiti personalizzati.
Ad esempio, se vuoi rendere un elemento secondario grande quanto l'elemento principale Box senza influire sulle dimensioni di Box, utilizza il modificatore matchParentSize. matchParentSize è disponibile solo in
BoxScope.
Pertanto, può essere utilizzato solo su un elemento secondario all'interno di un elemento principale Box.
La sicurezza dell'ambito ti impedisce di aggiungere modificatori che non funzionerebbero in altri composabili e ambiti e ti fa risparmiare tempo evitando di procedere per tentativi.
I modificatori con ambito comunicano al genitore alcune informazioni che dovrebbe conoscere sul figlio. Questi sono anche comunemente chiamati modificatori dei dati principali. I loro elementi 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 in precedenza, se vuoi che un layout secondario abbia le stesse dimensioni di un Box principale 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 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 venisse utilizzato fillMaxSize anziché matchParentSize, Spacer occuperebbe tutto lo spazio disponibile consentito per l'elemento principale, che a sua volta si espanderebbe e riempirebbe 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 componibile sono definite dai contenuti che racchiude. Puoi impostare una dimensione composable in modo che sia flessibile all'interno del suo elemento principale utilizzando il modificatore weight, disponibile solo in RowScope e ColumnScope.
Prendiamo un Row che contiene due componibili Box.
La prima casella ha un valore weight doppio 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 migliorare un componibile. Questa catena viene creata tramite l'interfaccia Modifier, che rappresenta un elenco ordinato e immutabile di singole Modifier.Elements.
Ogni Modifier.Element rappresenta un comportamento individuale, come il layout, il disegno e i comportamenti grafici, tutti i comportamenti relativi ai gesti, allo stato attivo e alla semantica, nonché gli 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ù composabili, 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 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 workload che il runtime di Compose deve eseguire durante il confronto
- Questa estrazione promuove la pulizia, la coerenza e la manutenibilità del codice all'interno del codebase
Best practice per il riutilizzo dei modificatori
Crea le tue catene Modifier ed estraile per riutilizzarle su più componenti componibili. È perfettamente accettabile salvare solo un modificatore, poiché 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 di frequente
Quando si osservano stati che cambiano di frequente all'interno di composabili, come gli stati di animazione o scrollState, è possibile che vengano eseguite molte 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 ) }
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 essere senza ambito o con ambito limitato a un composable specifico. Nel caso di modificatori senza ambito, puoi estrarli facilmente all'esterno di qualsiasi componibile come semplici variabili:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Questo può essere particolarmente utile se combinato con i layout Lazy. Nella maggior parte dei casi, vorrai che tutti i tuoi articoli, potenzialmente numerosi, 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 utilizzi modificatori con ambito limitato a determinati composabili, 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 passare i modificatori con ambito estratti solo agli elementi secondari diretti con lo stesso ambito. Per saperne di più sul motivo per cui questo è importante, consulta la sezione Sicurezza degli ambiti 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 concatenamento 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 fare più pratica sull'utilizzo dei modificatori, puoi anche consultare il codelab Layout di base in Compose o il 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 Compose
- Azioni dell'editor {:#editor-actions}
- Layout personalizzati {:#custom-layouts }