I modificatori ti consentono di decorare o aumentare un composable. I modificatori ti consentono di fare questo tipo di cose:
- Modificare le dimensioni, il layout, il comportamento e l'aspetto del composable
- Aggiungere informazioni, ad esempio le etichette di accessibilità
- Elabora l'input dell'utente
- Aggiungi interazioni di alto livello, ad esempio rendendo un elemento selezionabile, scorrevole, trascinabile o con zoom
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, noterai diverse funzioni di modificatore utilizzate insieme.
padding
inserisce uno spazio intorno a un elemento.fillMaxWidth
fa in modo che il composable raggiunga la larghezza massima assegnata dall'elemento principale.
È buona prassi che tutti i composabili accettino un parametro modifier
e trasmettano questo modificatore al primo elemento secondario che emette l'interfaccia utente.
In questo modo, il codice sarà più riutilizzabile e il suo comportamento sarà più prevedibile e intuitivo. Per maggiori 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 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 riportato sopra, l'intera area è selezionabile, incluso il padding circostante, perché il modificatore padding
è stato applicato dopo il modificatore clickable
. Se l'ordine degli modificatori è 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 composable. Ecco alcuni modificatori comuni che utilizzerai per modificare i layout.
padding
e size
Per impostazione predefinita, i layout forniti in Compose inseriscono un a capo nei 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 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 riempia 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
.
Se vuoi aggiungere un'area di a capo 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 sull'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 cambia 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 offset
positivo sposta l'elemento verso destra, mentre in un contesto da destra a sinistra, lo sposta verso 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 verso la
sinistra.
Il modificatore offset
fornisce due sovraccarichi: offset
che prende gli offset come parametri e offset
che prende una lambda.
Per informazioni più dettagliate su quando utilizzare ciascuna di queste opzioni e su come ottimizzare il rendimento, consulta la sezione Rendimento di Compose: rimanda le letture il più a lungo possibile.
Sicurezza dell'ambito in Compose
In Compose, esistono modificatori che possono essere utilizzati solo se applicati ai figli di determinati composabili. Compose applica questo principio tramite ambiti personalizzati.
Ad esempio, se vuoi rendere un elemento figlio 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 in 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 tentativi ed errori.
I modificatori basati sugli ambiti informano il genitore su alcune informazioni che deve conoscere sul figlio. Sono noti anche come modificatori dei dati principali. I relativi componenti interni sono diversi da quelli dei modificatori di uso generale, 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 principaleBox
senza influire sulle dimensioni di Box
, utilizza il modificatore matchParentSize
.
Tieni presente che matchParentSize
è disponibile solo nell'ambito di un ambito Box
, il che significa che si applica solo agli elementi secondari diretti dei composabili Box
.
Nell'esempio seguente, l'elemento secondario Spacer
eredita le dimensioni dall'elemento principale Box
, che a sua volta le eredita dall'elemento secondario più grande, in questo caso ArtistCard
.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
Se al posto di matchParentSize
fosse stato utilizzato fillMaxSize
, Spacer
occuperebbe tutto lo spazio disponibile consentito al contenitore, che a sua volta si espanderebbe e riempirebbe tutto lo spazio disponibile.
weight
in Row
e Column
Come hai visto nella sezione precedente relativa a Spaziatura interna e dimensione, per impostazione predefinita, le dimensioni di un componente componibile sono definite dai contenuti che vengono a capo. Puoi impostare le dimensioni di un componibile in modo che siano flessibili all'interno del suo elemento primario utilizzando il modificatore weight
, disponibile solo in RowScope
e ColumnScope
.
Prendiamo un Row
contenente due composabili Box
.
La prima casella ha un weight
doppio rispetto alla seconda, quindi ha anche 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 composable. Questa catena viene creata tramite l'interfaccia Modifier
, che rappresenta un elenco ordinato e immutabile di singoli Modifier.Elements
.
Ogni Modifier.Element
rappresenta un singolo comportamento, come i comportamenti relativi a layout, disegno e grafica, tutti i comportamenti relativi a gesti, messa a fuoco e 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 di catena di modificatori in più composabili estraendoli in variabili e aggiungendoli a ambiti superiori. 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 quando si verifica la ricompozione per i composabili che li utilizzano
- Le catene di modificatori potrebbero essere potenzialmente molto lunghe e complesse, quindi il riutilizzo della stessa istanza di una catena può alleggerire il carico di lavoro necessario per il runtime di Compose quando le confronta.
- Questa estrazione favorisce la pulizia, la coerenza e la manutenibilità del codice in tutta la base di codice
Best practice per il riutilizzo dei modificatori
Crea le tue catene Modifier
ed estraile per riutilizzarle su più componenti composibili. È perfettamente possibile salvare solo un modificatore, poiché si tratta di oggetti simili ai dati:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
Estrazione e riutilizzo dei modificatori quando si osserva uno stato in continua evoluzione
Quando si osservano stati che cambiano di frequente all'interno dei composabili, come gli stati di animazione o scrollState
, può essere eseguita una quantità significativa di ricostruzioni. In questo caso, i modificatori verranno allocati a ogni ricomposizio
e potenzialmente per ogni fotogramma:
@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 composable come segue:
// 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 di modificatori senza ambito
I modificatori possono essere senza ambito o avere un ambito specifico per un composable. Nel caso dei modificatori senza ambito, puoi estrarli facilmente al di fuori di qualsiasi composable come semplici variabili:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
Questa funzionalità può essere particolarmente utile se combinata con i layout lazy. Nella maggior parte dei casi, è consigliabile che tutti gli elementi, potenzialmente significativi, abbiano 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 sugli ambiti
Quando hai a che fare con modificatori che hanno come ambito determinati composabili, puoi estrarli al livello più alto possibile e riutilizzarli ove 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 estratto solo ai figli diretti con lo stesso ambito. Per ulteriori informazioni sul motivo per cui questo è 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 // ... ) } }
Catena aggiuntiva di modificatori estratti
Puoi concatenare ulteriormente o aggiungere le catene di modificatori estratti 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 sull'utilizzo dei modificatori, puoi anche consultare il codelab sui layout di base in Compose o fare riferimento al repository Ora in Android.
Per ulteriori informazioni sui modificatori personalizzati e su come crearli, consulta la documentazione su Layout personalizzati - Utilizzo del modificatore del 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 }