Con Jetpack Compose, è molto più semplice progettare e creare l'UI della tua app. Compose trasforma lo stato in elementi UI tramite:
- Composizione degli elementi
- Layout degli elementi
- Disegno di elementi
Questo documento è incentrato sul layout degli elementi e spiega alcuni dei componenti di base forniti da Compose per aiutarti a disporre gli elementi dell'interfaccia utente.
Obiettivi dei layout in Compose
L'implementazione del sistema di layout con 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 base di Compose. Una funzione componibile è una funzione che emette Unit
che descrive parte della UI. La funzione
riceve un input e genera ciò che viene mostrato sullo schermo. Per ulteriori informazioni sugli elementi componibili, consulta la documentazione di Compose mental model.
Una funzione componibile può emettere diversi elementi UI. Tuttavia, se non fornisci indicazioni su come devono essere disposti, Compose potrebbe disporre gli elementi in un modo non soddisfacente. Ad esempio, questo codice genera due elementi di testo:
@Composable fun ArtistCard() { Text("Alfred Sisley") Text("3 minutes ago") }
Senza indicazioni su come vuoi che vengano disposti, Compose impila gli elementi di testo uno sopra l'altro, rendendoli illeggibili:
Compose fornisce una raccolta di layout pronti all'uso per aiutarti a organizzare gli elementi dell'interfaccia utente e a definire layout più specifici.
Componenti del layout standard
In molti casi, puoi utilizzare solo gli elementi di layout standard di Compose.
Utilizza Column
per posizionare gli elementi in verticale sullo schermo.
@Composable fun ArtistCardColumn() { Column { Text("Alfred Sisley") Text("3 minutes ago") } }
Analogamente, 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 posizionare gli elementi sopra un altro. Box
supporta anche la configurazione dell'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 componenti di base sono sufficienti. 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 elemento Row
, imposta gli argomenti horizontalArrangement
e
verticalAlignment
. Per 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, la struttura ad albero dell'interfaccia utente è disposti in un'unica passaggio. A ogni nodo viene prima chiesto di misurare se stesso, quindi misurare eventuali figli in modo ricorsivo, passando i vincoli di dimensione dell'albero agli elementi secondari. Quindi, vengono ridimensionati e posizionati i nodi foglia, con le dimensioni risolte e le istruzioni di posizionamento ritrasmessi nell'albero.
In breve, i genitori misurano la misurazione prima dei figli, ma la loro taglia e la loro posizione dopo i loro figli.
Considera la seguente funzione SearchResult
.
@Composable fun SearchResult() { Row { Image( // ... ) Column { Text( // ... ) Text( // ... ) } } }
Questa funzione restituisce il seguente albero dell'interfaccia utente.
SearchResult
Row
Image
Column
Text
Text
Nell'esempio SearchResult
, il layout ad albero dell'interfaccia utente segue questo ordine:
- Viene richiesto di misurare il nodo radice
Row
. - Il nodo radice
Row
chiede al suo primo nodo secondario,Image
, di misurare. Image
è un nodo foglia (ovvero non ha elementi secondari), quindi riporta una dimensione e restituisce istruzioni per il posizionamento.- Il nodo radice
Row
chiede al suo secondo figlio,Column
, di eseguire la misurazione. - Il nodo
Column
chiede al suo primoText
elemento figlio da misurare. - Il primo nodo
Text
è un nodo foglia, quindi segnala una dimensione e restituisce istruzioni di posizionamento. - Il nodo
Column
chiede al suo secondo elemento secondarioText
di misurare. - Il secondo nodo
Text
è un nodo foglia, quindi segnala una dimensione e restituisce istruzioni di posizionamento. - Ora che il nodo
Column
ha misurato, ridimensionato e posizionato i propri elementi figlio, può determinare le proprie dimensioni e il proprio posizionamento. - Ora che il nodo radice
Row
ha misurato, ridimensionato e posizionato i nodi figlio, può determinare le proprie dimensioni e il proprio posizionamento.
Esibizione
Compose raggiunge prestazioni elevate misurando i bambini una sola volta. La misurazione a passaggio singolo è un'ottima soluzione per le prestazioni, consentendo a Compose di gestire in modo efficiente alberi UI profonde. Se un elemento misurasse l'elemento figlio due volte e quest'ultimo ne misurasse ciascuno due volte e così via, un singolo tentativo di strutturare un'intera UI avrebbe richiesto molto lavoro, rendendo difficile mantenere le prestazioni dell'app.
Se per qualche motivo il layout richiede più misurazioni, Compose offre un sistema speciale: le misure intrinseche. Per saperne di più su questa funzionalità, consulta Misurazioni intrinseche nei layout di Scrivi.
Poiché la misurazione e il posizionamento sono sottofasi distinte del passaggio del layout, qualsiasi modifica che interessa solo il posizionamento degli elementi, non la misurazione, può essere eseguita separatamente.
Utilizzare i modificatori nei layout
Come spiegato in Modificatori di Scrivi, puoi utilizzarli per decorare o arricchire i tuoi componibili. 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, puoi notare che le diverse funzioni di modifica sono utilizzate insieme.
clickable
genera una reazione componibile all'input dell'utente e mostra un'onda.padding
inserisce uno spazio intorno a un elemento.fillMaxWidth
consente al componibile di riempire la larghezza massima assegnata dal relativo elemento principale.size()
specifica la larghezza e l'altezza preferite per un elemento.
Layout scorrevoli
Scopri di più sui layout scorrevoli nella documentazione relativa ai gesti di Scrivi.
Per gli elenchi e gli elenchi lenti, consulta la documentazione relativa agli elenchi di composizione.
Layout adattabili
Il layout deve essere progettato tenendo conto di orientamento dello schermo e dimensioni dei fattori di forma diversi. Compose offre alcuni meccanismi pronti all'uso per facilitare l'adattamento dei layout componibili a varie configurazioni dello schermo.
Vincoli
Per conoscere i vincoli derivanti dall'elemento padre e progettare il layout di conseguenza, puoi utilizzare un BoxWithConstraints
. I vincoli di misurazione si trovano nell'ambito della funzione 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 su slot
Compose offre un'ampia gamma di elementi componibili basati su Material
Design con la dipendenza
androidx.compose.material:material
(inclusa quando si crea un
progetto Scrivi in Android Studio) per semplificare la creazione di UI. Elementi come
Drawer
,
FloatingActionButton
e TopAppBar
sono tutti forniti.
I componenti del materiale fanno un uso intensivo delle API slot, un pattern introdotto da Compose per aggiungere un livello di personalizzazione ai componenti componibili. Questo approccio rende i componenti più flessibili, poiché accettano un elemento secondario che può configurare da sé, invece di dover esporre ogni parametro di configurazione dell'elemento figlio.
Le aree lasciano uno spazio vuoto nell'interfaccia utente che lo sviluppatore potrà riempire come desidera. Ad esempio, di seguito sono riportate le aree che puoi personalizzare in una TopAppBar
:
I componibili di solito utilizzano una funzione lambda componibile content
( content: @Composable
() -> Unit
). Le API slot espongono più parametri content
per usi specifici.
Ad esempio, TopAppBar
ti consente di fornire i contenuti di title
, navigationIcon
e actions
.
Ad esempio,
Scaffold
consente di implementare un'interfaccia utente con la struttura di base del layout di Material Design.
Scaffold
fornisce spazi per i componenti Material di primo livello più comuni,
come TopAppBar
,
BottomAppBar
,
FloatingActionButton
e Drawer
. Se utilizzi Scaffold
, è facile assicurarsi che questi componenti siano posizionati correttamente e funzionino insieme correttamente.
@Composable fun HomeScreen(/*...*/) { ModalNavigationDrawer(drawerContent = { /* ... */ }) { Scaffold( topBar = { /*...*/ } ) { contentPadding -> // ... } } }
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Modificatori di Scrivi
- Kotlin per Jetpack Compose
- Componenti e layout Material