ConstraintLayout è un layout che ti consente di posizionare i composable rispetto
ad altri composable sullo schermo. È un'alternativa all'utilizzo di più elementi di layout personalizzati
Row, Column, Box e altri elementi di layout personalizzati.
Nel sistema View, ConstraintLayout era il modo consigliato per creare layout grandi e complessi, in quanto una gerarchia di oggetti View 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, quindi ConstraintLayout non è così
vantaggioso.
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 tra loro in un
ConstraintLayout.
API disaccoppiata
Nell'esempio ConstraintLayout, i vincoli vengono specificati in linea, con un
modificatore nel componibile 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 il passaggio tra due insiemi di vincoli.
Per casi come questi, puoi utilizzare ConstraintLayout in un altro modo:
- Passa 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 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. I due orizzontali sono top e bottom, mentre i 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 combinabili 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 uniformemente tra tutti i composable, senza spazio libero prima del primo composable o dopo l'ultimo composable.ChainStyle.Packed: lo spazio viene distribuito prima del primo e dopo l'ultimo elemento componibile, che vengono raggruppati senza spazio tra l'uno e l'altro.