Jetpack Compose semplifica notevolmente la progettazione e la creazione della UI della tua app. Compose trasforma lo stato in elementi UI tramite:
- Composizione degli elementi
- Layout degli elementi
- Disegno degli elementi
Questo documento si concentra sul layout degli elementi, spiegando alcuni dei blocchi di costruzione forniti da Compose per aiutarti a disporre gli elementi dell'interfaccia utente.
Obiettivi dei layout in Scrivi
L'implementazione del sistema di layout di Jetpack Compose ha due obiettivi principali:
- Prestazioni elevate
- Possibilità di scrivere facilmente layout personalizzati
Nozioni di base sulle funzioni componibili
Le funzioni componibili sono l'elemento di base di Compose. Una funzione
componibile è una funzione che emette Unit
che descrive una parte della tua UI. La
funzione accetta alcuni input e genera ciò che viene mostrato sullo schermo. Per saperne di più sui composable, consulta la documentazione sul modello mentale di Compose.
Una funzione componibile può emettere diversi elementi dell'interfaccia utente. Tuttavia, se non fornisci indicazioni su come devono essere disposti, Compose potrebbe disporre gli elementi in un modo che non ti piace. Ad esempio, questo codice genera due elementi di testo:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
Senza indicazioni su come disporli, Crea impila gli elementi di testo uno sopra l'altro, rendendoli illeggibili:
Compose offre una raccolta di layout pronti all'uso per aiutarti a disporre gli elementi dell'interfaccia utente e semplifica la definizione di layout più specializzati.
Componenti del layout standard
In molti casi, puoi semplicemente utilizzare gli elementi di layout standard di Compose.
Utilizza
Column
per posizionare gli elementi verticalmente sullo schermo.
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
Allo stesso modo, utilizza
Row
per posizionare gli elementi orizzontalmente sullo schermo. Sia Column
che Row
supportano
la configurazione dell'allineamento degli elementi che contengono.
@Composable fun ArtistCardRow(artist: Artist) { Row(verticalAlignment = Alignment.CenterVertically) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { Text(artist.name) Text(artist.lastSeenOnline) } } }
Utilizza Box
per sovrapporre gli elementi. Box
supporta anche la configurazione di un allineamento specifico degli elementi che contiene.
@Composable fun ArtistAvatar(artist: Artist) { Box { Image(bitmap = artist.image, contentDescription = "Artist image") Icon(Icons.Filled.Check, contentDescription = "Check mark") } }
Spesso questi elementi di base sono tutto ciò di cui hai bisogno. Puoi scrivere la tua funzione componibile per combinare questi layout in un layout più elaborato adatto alla tua app.
Per impostare la posizione dei bambini all'interno di un Row
, imposta gli argomenti horizontalArrangement
e
verticalAlignment
. Per un Column
, imposta gli argomenti verticalArrangement
e
horizontalAlignment
:
@Composable fun ArtistCardArrangement(artist: Artist) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ) { Image(bitmap = artist.image, contentDescription = "Artist image") Column { /*...*/ } } }
Il modello di layout
Nel modello di layout, l'albero della UI viene disposto in un unico passaggio. A ogni nodo viene prima chiesto di misurarsi, poi di misurare ricorsivamente gli elementi secondari, passando i vincoli di dimensione verso il basso dell'albero agli elementi secondari. Quindi, le dimensioni e il posizionamento dei nodi foglia vengono risolti e le istruzioni relative a dimensioni e posizionamento vengono trasmesse di nuovo all'albero.
In breve, i genitori vengono misurati prima dei figli, ma vengono posizionati dopo i figli.
Considera la seguente funzione SearchResult
.
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
Questa funzione genera il seguente albero dell'interfaccia utente.
SearchResult
Row
Image
Column
Text
Text
Nell'esempio SearchResult
, il layout dell'albero della UI segue questo ordine:
- Al nodo principale
Row
viene chiesto di eseguire la misurazione. - Il nodo radice
Row
chiede al suo primo elemento secondario,Image
, di misurare. Image
è un nodo foglia (ovvero non ha elementi secondari), quindi segnala una dimensione e restituisce le istruzioni di posizionamento.- Il nodo radice
Row
chiede al suo secondo figlio,Column
, di misurare. - Il nodo
Column
chiede al suo primo elemento secondarioText
di eseguire la misurazione. - Il primo nodo
Text
è un nodo foglia, quindi segnala una dimensione e restituisce le istruzioni di posizionamento. - Il nodo
Column
chiede al secondo nodo secondarioText
di eseguire la misurazione. - Il secondo nodo
Text
è un nodo foglia, quindi segnala una dimensione e restituisce le istruzioni di posizionamento. - Ora che il nodo
Column
ha misurato, dimensionato e posizionato i suoi figli, può determinare le proprie dimensioni e il proprio posizionamento. - Ora che il nodo radice
Row
ha misurato, dimensionato e posizionato i suoi figli, può determinare le proprie dimensioni e il proprio posizionamento.
Prestazioni
Compose raggiunge prestazioni elevate misurando i figli una sola volta. La misurazione a singola passata è utile per le prestazioni, in quanto consente a Compose di gestire in modo efficiente alberi dell'interfaccia utente complessi. Se un elemento ha misurato il suo elemento secondario due volte e quest'ultimo ha misurato ciascuno dei suoi elementi secondari due volte e così via, un singolo tentativo di disporre un'intera UI dovrebbe richiedere molto lavoro, rendendo difficile mantenere le prestazioni dell'app.
Se il layout richiede più misurazioni per qualche motivo, Compose offre un sistema speciale, le misurazioni intrinseche. Puoi scoprire di più su questa funzionalità in Misurazioni intrinseche nei layout di Compose.
Poiché la misurazione e il posizionamento sono sottofasi distinte del passaggio del layout, qualsiasi modifica che influisce solo sul posizionamento degli elementi, non sulla misurazione, può essere eseguita separatamente.
Utilizzare i modificatori nei layout
Come descritto in Modificatori di composizione, puoi utilizzare
i modificatori per decorare o aumentare i tuoi composable. I modificatori sono essenziali
per personalizzare il layout. Ad esempio, qui concateniamo diversi modificatori
per personalizzare ArtistCard
:
@Composable fun ArtistCardModifiers( artist: Artist, onClick: () -> Unit ) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { Row(verticalAlignment = Alignment.CenterVertically) { /*...*/ } Spacer(Modifier.size(padding)) Card( elevation = CardDefaults.cardElevation(defaultElevation = 4.dp), ) { /*...*/ } } }
Nel codice riportato sopra, nota le diverse funzioni di modifica utilizzate insieme.
clickable
rende un elemento componibile reattivo all'input dell'utente e mostra un'increspatura.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.size()
specifica la larghezza e l'altezza preferite di un elemento.
Layout scorrevoli
Scopri di più sui layout scorrevoli nella documentazione sui gesti di composizione.
Per elenchi e elenchi pigri, consulta la documentazione su come comporre elenchi.
Layout adattabili
Un layout deve essere progettato tenendo conto dei diversi orientamenti dello schermo e delle dimensioni del fattore di forma. Compose offre alcuni meccanismi predefiniti per facilitare l'adattamento dei layout componibili a varie configurazioni dello schermo.
Vincoli
Per conoscere i vincoli del contenitore principale e progettare il layout
di conseguenza, puoi utilizzare un BoxWithConstraints
. I vincoli di misurazione sono disponibili nell'ambito della lambda dei contenuti. Puoi utilizzare questi vincoli di misurazione per comporre layout diversi per configurazioni dello schermo diverse:
@Composable fun WithConstraintsComposable() { BoxWithConstraints { Text("My minHeight is $minHeight while my maxWidth is $maxWidth") } }
Layout basati sugli slot
Compose offre un'ampia gamma di componenti componibili basati su Material
Design con la
dipendenza androidx.compose.material:material
(inclusa quando crei un
progetto Compose in Android Studio) per semplificare la creazione dell'interfaccia utente. Sono forniti tutti gli elementi come
Drawer
,
FloatingActionButton
,
e TopAppBar
.
I componenti Material utilizzano molto le API slot, un pattern introdotto da Compose
per aggiungere un livello di personalizzazione sopra i composable. Questo approccio rende i componenti più flessibili, in quanto accettano un elemento secondario che può configurarsi autonomamente anziché dover esporre ogni parametro di configurazione del componente secondario.
Gli slot lasciano uno spazio vuoto nell'interfaccia utente che lo sviluppatore può riempire a suo piacimento. Ad
esempio, questi sono gli slot che puoi personalizzare in un
TopAppBar
:
I composable in genere accettano una lambda composable ( content: @Composable
() -> Unit
). Le API slot espongono più parametri content
per usi specifici.content
Ad esempio, TopAppBar
ti consente di fornire i contenuti per title
,
navigationIcon
e actions
.
Ad esempio,
Scaffold
ti consente di implementare una UI con la struttura di layout di base di Material Design.
Scaffold
fornisce slot per i componenti Material di primo livello più comuni,
come TopAppBar
,
BottomAppBar
,
FloatingActionButton
e Drawer
. Utilizzando
Scaffold
, è facile assicurarsi che questi componenti siano posizionati correttamente e
funzionino insieme in modo corretto.
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori di composizione
- Kotlin per Jetpack Compose
- Componenti e layout di Material