ConstraintLayout è un layout che ti consente di posizionare i componenti componibili rispetto
ad altri componenti componibili sullo schermo. È un'alternativa all'utilizzo di più elementi di layout personalizzati Row, Column, Box e altri nidificati. ConstraintLayout
è utile quando implementi layout più grandi con requisiti di allineamento più complessi.
Prendi in considerazione l'utilizzo di ConstraintLayout nei seguenti scenari:
- Per evitare di nidificare più
ColumneRowper posizionare gli elementi sullo schermo e migliorare la leggibilità del codice. - Per posizionare i composable rispetto ad altri composable o in base a linee guida, barriere o catene.
In View system, ConstraintLayout era il modo consigliato per creare layout grandi e complessi, in quanto una gerarchia di visualizzazione 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:$constraintlayout_compose_version"
ConstraintLayout in Scrittura Magica funziona nel seguente modo utilizzando un
DSL:
- Crea riferimenti per ogni componibile in
ConstraintLayoututilizzandocreateRefs()ocreateRefFor(). - I vincoli vengono forniti utilizzando il modificatore
constrainAs(), che accetta il riferimento come parametro e consente di specificarne i vincoli nel corpo della lambda. - I vincoli vengono specificati utilizzando
linkTo()o altri metodi utili. parentè un riferimento esistente che può essere utilizzato per specificare vincoli verso il componibileConstraintLayoutstesso.
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 padre con un margine di
16.dp e un Text alla parte inferiore di Button, anch'esso con un margine di
16.dp.
Button e un Text componibili vincolati l'uno all'altro in un
ConstraintLayout.
API disaccoppiata
Nell'esempio ConstraintLayout,
i vincoli vengono specificati inline, con un modificatore nel composable a cui
vengono applicati. Tuttavia, ci sono situazioni in cui è preferibile separare i vincoli dai layout a cui si applicano. Ad esempio, potresti voler
modificare i vincoli in base alla configurazione dello schermo o animare due
set di vincoli.
Per casi come questi, puoi utilizzare ConstraintLayout in un altro modo:
- Trasmetti un
ConstraintSetcome parametro aConstraintLayout. - Assegna i riferimenti creati in
ConstraintSetai 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 passare un ConstraintSet diverso.
ConstraintLayout concetti
ConstraintLayout contiene concetti come linee guida, barriere e catene
che possono aiutarti a posizionare gli elementi all'interno del tuo componente.
Linee guida
Le guide sono piccoli aiuti visivi per progettare i layout. I composable possono essere
vincolati a una linea guida. Le guide sono utili per posizionare gli elementi a una
determinata dp o percentage all'interno del composable principale.
Esistono due tipi diversi 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
richiesto. In questo modo viene creato un riferimento che può essere utilizzato nel blocco Modifier.constrainAs().
Barriere
Barriere fa riferimento a più componenti 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
devono costituire 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 forniscono un comportamento simile a quello dei gruppi in un singolo asse (orizzontalmente o verticalmente). 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 decidono come
gestire lo spazio che circonda un componente componibile, ad esempio:
ChainStyle.Spread: lo spazio è distribuito uniformemente tra tutti i componenti componibili, incluso lo spazio libero prima del primo componente componibile e dopo l'ultimo componente componibile.ChainStyle.SpreadInside: lo spazio è distribuito in modo uniforme tra tutti i composable, senza spazi liberi prima del primo composable o dopo l'ultimo composable.ChainStyle.Packed: lo spazio viene distribuito prima del primo e dopo l'ultimo composable, i composable sono raggruppati senza spazio tra l'uno e l'altro.
Scopri di più
Scopri di più su ConstraintLayout in Compose dagli esempi di API in azione negli
esempi di Compose che utilizzano ConstraintLayout.