ConstraintLayout
è un layout che consente di posizionare elementi componibili rispetto ad altri componibili sullo schermo. Si tratta di un'alternativa all'utilizzo di più
Row
, Column
, Box
e altri elementi di layout personalizzati nidificati. ConstraintLayout
è utile per l'implementazione di layout più grandi con requisiti di
allineamento più complicati.
Valuta la possibilità di utilizzare ConstraintLayout
nei seguenti scenari:
- evitare di nidificare più
Column
eRow
per il posizionamento degli elementi sullo schermo in modo da migliorare la leggibilità del codice. - Posizionare i componibili rispetto ad altri componibili o posizionare i componibili in base a linee guida, barriere o catene.
Nel sistema di visualizzazione, ConstraintLayout
era il metodo consigliato per creare layout complessi e di grandi dimensioni, poiché una gerarchia di visualizzazione piatta offriva prestazioni migliori rispetto alle viste nidificate. Tuttavia, questo non è un problema in Compose, che è in grado di
gestire in modo efficiente le gerarchie di layout più profonde.
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 Compose funziona nel seguente modo utilizzando una
DSL:
- Crea riferimenti per ogni componibile in
ConstraintLayout
utilizzandocreateRefs()
ocreateRefFor()
- I vincoli vengono forniti utilizzando il modificatore
constrainAs()
, che prende il riferimento come parametro e consente di specificarne i vincoli nel corpo lambda. - I vincoli vengono specificati utilizzando
linkTo()
o altri metodi utili. parent
è un riferimento esistente che può essere utilizzato per specificare vincoli rispetto all'elemento componibileConstraintLayout
stesso.
Ecco un esempio di componibile che utilizza un elemento 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 del Button
all'elemento principale con un margine di
16.dp
e un Text
alla fine del Button
anch'esso con un margine di
16.dp
.
API disaccoppiata
Nell'esempio ConstraintLayout
, i vincoli sono specificati in linea, con un modificatore nell'elemento componibile a cui vengono applicati. Tuttavia, in alcune situazioni è preferibile disaccoppiare i vincoli dai layout a cui si applicano. Ad esempio, potresti voler modificare i vincoli in base alla configurazione dello schermo o animare tra due insiemi di vincoli.
In casi come questi, puoi utilizzare ConstraintLayout
in un altro modo:
- Passa un elemento
ConstraintSet
come parametro aConstraintLayout
. - Assegna i riferimenti creati in
ConstraintSet
ai componibili 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 i vincoli, puoi semplicemente trasmettere un ConstraintSet
diverso.
ConstraintLayout
concetti
ConstraintLayout
contiene concetti quali linee guida, barriere e catene
che possono aiutarti a posizionare gli elementi all'interno dell'elemento componibile.
Linee guida
Le linee guida sono dei piccoli aiutanti visivi con cui progettare i layout. I componibili possono essere
vincolati a una linea guida. Le linee guida sono utili per posizionare gli elementi in un determinato elemento dp
o percentage
all'interno dell'elemento componibile principale.
Esistono due diversi tipi di linee guida: verticali e orizzontali. Le due
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 obbligatoria. Viene creato un riferimento che può essere utilizzato nel blocco Modifier.constrainAs()
.
Barriere
Le barriere fanno riferimento a più elementi componibili per creare una linea guida virtuale basata sul widget più estremo sul lato specificato.
Per creare una barriera, utilizza createTopBarrier()
(o createBottomBarrier()
,
createEndBarrier()
, createStartBarrier()
) e fornisci i riferimenti che
dovrebbero comporre la barriera.
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 offrono un comportamento di tipo gruppo su 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 ChainStyles
diverse, che decidono come gestire
lo spazio che circonda un componibile, ad esempio:
ChainStyle.Spread
: lo spazio viene distribuito uniformemente tra tutti i componibili, compreso lo spazio libero prima del primo componibile e dopo l'ultimo.ChainStyle.SpreadInside
: lo spazio viene distribuito uniformemente tra tutti i componibili, senza alcuno spazio libero prima del primo componibile o dopo l'ultimo.ChainStyle.Packed
: lo spazio viene distribuito prima del primo e dopo l'ultimo, gli elementi componibili vengono componibili senza spazi l'uno dall'altro.
Scopri di più
Scopri di più su ConstraintLayout
in Compose dalle API in azione nella sezione
Esempi di Compose che utilizzano ConstraintLayout
.
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Messa a fuoco in Compose
- Kotlin per Jetpack Compose
- Nozioni di base sul layout di scrittura