ConstraintLayout
è un layout che ti consente di posizionare i composabili rispetto ad altri composabili sullo schermo. È un'alternativa all'utilizzo di più elementi personalizzati di layout Row
, Column
, Box
e altri elementi di layout personalizzati nidificati. ConstraintLayout
è utile per implementare layout più grandi con requisiti di allineamento più complicati.
Valuta la possibilità di utilizzare ConstraintLayout
nei seguenti scenari:
- Per evitare di nidificare più
Column
eRow
per posizionare gli elementi sullo schermo, migliora la leggibilità del codice. - Per posizionare i composabili rispetto ad altri composabili o per posizionare i composabili in base a linee guida, barriere o catene.
Nel sistema di visualizzazione, ConstraintLayout
era il metodo consigliato per creare layout grandi e complessi, in quanto una gerarchia di visualizzazioni piatta era migliore per il rendimento rispetto alle visualizzazioni nidificate. Tuttavia, questo non è un problema in Compose, che è in grado di gestire in modo efficiente gerarchie di layout complesse.
Inizia a utilizzare ConstraintLayout
Per utilizzare ConstraintLayout
in Compose, devi aggiungere questa dipendenza in build.gradle
(oltre alla configurazione di Compose):
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
ConstraintLayout
in Scrittura funziona nel seguente modo utilizzando un
DSL:
- Crea riferimenti per ogni composable in
ConstraintLayout
utilizzandocreateRefs()
ocreateRefFor()
- I vincoli vengono forniti utilizzando il modificatore
constrainAs()
, che prende il riferimento come parametro e ti consente di specificare i relativi vincoli nel corpo della funzione lambda. - I vincoli vengono specificati utilizzando
linkTo()
o altri metodi utili. parent
è un riferimento esistente che può essere utilizzato per specificare vincoli nei confronti del componibileConstraintLayout
stesso.
Ecco un esempio di composable che utilizza un ConstraintLayout
:
@Composable fun ConstraintLayoutContent() { ConstraintLayout { // Create references for the composables to constrain val (button, text) = createRefs() Button( onClick = { /* Do something */ }, // Assign reference "button" to the Button composable // and constrain it to the top of the ConstraintLayout modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } // Assign reference "text" to the Text composable // and constrain it to the bottom of the Button composable Text( "Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) } ) } }
Questo codice vincola la parte superiore di Button
all'elemento principale con un margine di
16.dp
e un Text
alla parte inferiore di Button
, sempre con un margine di
16.dp
.
API disaccoppiata
Nell'esempio ConstraintLayout
,
i vincoli sono specificati in linea, con un modificatore nel composable a cui vengono
applicati. Tuttavia, in alcune situazioni è preferibile disaccoppiare i vincoli dai layout a cui si applicano. Ad esempio, potresti voler cambiare i vincoli in base alla configurazione dello schermo o animare tra due insiemi di vincoli.
Per casi come questi, puoi utilizzare ConstraintLayout
in un modo diverso:
- Passa un
ConstraintSet
come parametro aConstraintLayout
. - Assegna i riferimenti creati in
ConstraintSet
ai composabili utilizzando il modificatorelayoutId
.
@Composable fun DecoupledConstraintLayout() { BoxWithConstraints { val constraints = if (minWidth < 600.dp) { decoupledConstraints(margin = 16.dp) // Portrait constraints } else { decoupledConstraints(margin = 32.dp) // Landscape constraints } ConstraintLayout(constraints) { Button( onClick = { /* Do something */ }, modifier = Modifier.layoutId("button") ) { Text("Button") } Text("Text", Modifier.layoutId("text")) } } } private fun decoupledConstraints(margin: Dp): ConstraintSet { return ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") constrain(button) { top.linkTo(parent.top, margin = margin) } constrain(text) { top.linkTo(button.bottom, margin) } } }
Poi, quando devi modificare le limitazioni, puoi semplicemente passare un valore ConstraintSet
diverso.
Concetti di ConstraintLayout
ConstraintLayout
contiene concetti come linee guida, barriere e catene
che possono aiutarti a posizionare gli elementi all'interno del tuo Composable.
Linee guida
Le linee guida sono piccoli ausili visivi per progettare i layout. I composabili possono essere vincolati a una linea guida. Le linee guida sono utili per posizionare gli elementi in un determinato dp
o percentage
all'interno del composable principale.
Esistono due tipi diversi di linee guida, verticali e orizzontali. Le due linee orizzontali sono top
e bottom
, mentre le due verticali sono start
e end
.
ConstraintLayout { // Create guideline from the start of the parent at 10% the width of the Composable val startGuideline = createGuidelineFromStart(0.1f) // Create guideline from the end of the parent at 10% the width of the Composable val endGuideline = createGuidelineFromEnd(0.1f) // Create guideline from 16 dp from the top of the parent val topGuideline = createGuidelineFromTop(16.dp) // Create guideline from 16 dp from the bottom of the parent val bottomGuideline = createGuidelineFromBottom(16.dp) }
Per creare una linea guida, utilizza createGuidelineFrom*
con il tipo di linea guida richiesto. Viene creato un riferimento che può essere utilizzato nel
blocco Modifier.constrainAs()
.
Barriere
Barriere fa riferimento a più composabili per creare una linea guida virtuale in base al widget più estremo sul lato specificato.
Per creare una barriera, utilizza createTopBarrier()
(o createBottomBarrier()
,
createEndBarrier()
, createStartBarrier()
) e fornisci i riferimenti che devono costituirla.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
La barriera può quindi essere utilizzata in un blocco Modifier.constrainAs()
.
Catene
Le catene forniscono un comportamento simile a quello di un gruppo in un singolo asse (orizzontale o verticale). L'altro asse può essere vincolato in modo indipendente.
Per creare una catena, utilizza createVerticalChain
o createHorizontalChain
:
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread) val horizontalChain = createHorizontalChain(button, text) } }
La catena può quindi essere utilizzata nel blocco Modifier.constrainAs()
.
Una catena può essere configurata con diversi ChainStyles
, che determinano come gestire lo spazio che circonda un composable, ad esempio:
ChainStyle.Spread
: lo spazio viene distribuito in modo uniforme tra tutti i composabili, incluso lo spazio libero prima del primo composable e dopo l'ultimo composable.ChainStyle.SpreadInside
: lo spazio viene distribuito in modo uniforme tra tutti i composabili, senza spazi vuoti prima del primo composable o dopo l'ultimo.ChainStyle.Packed
: lo spazio viene distribuito prima del primo e dopo l'ultimo composable, i composable sono raggruppati senza spazi tra loro.
Scopri di più
Scopri di più su ConstraintLayout
in Compose dalle API in azione nei
campioni di Compose che utilizzano ConstraintLayout
.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Mettere a fuoco in Scrittura
- Kotlin per Jetpack Compose
- Nozioni di base sul layout di composizione