ConstraintLayout ist ein Layout, mit dem Sie Composables relativ zu anderen Composables auf dem Bildschirm platzieren können. Es ist eine Alternative zur Verwendung mehrerer verschachtelter
Row, Column, Box, und anderer benutzerdefinierter Layout-Elemente.
Im View-System war ConstraintLayout die empfohlene Methode zum Erstellen großer und komplexer Layouts, da eine flache Ansichtshierarchie für die Leistung besser war als verschachtelte Ansichten. Dies ist jedoch in Compose kein Problem, da tiefe Layout-Hierarchien effizient verarbeitet werden können. Daher ist `ConstraintLayout` nicht so vorteilhaft.
Erste Schritte mit ConstraintLayout
Wenn Sie ConstraintLayout in Compose verwenden möchten, müssen Sie diese Abhängigkeit zusätzlich zur Compose-Einrichtung in
build.gradle hinzufügen:
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
ConstraintLayout in Compose funktioniert mit einer
DSL so:
- Erstellen Sie Referenzen für jedes Composable in der
ConstraintLayoutmitcreateRefs()odercreateRefFor(). - Einschränkungen werden mit dem Modifikator
constrainAs()angegeben, der die Referenz als Parameter verwendet. Sie können die Einschränkungen im Body-Lambda angeben. - Einschränkungen werden mit
linkTo()oder anderen hilfreichen Methoden angegeben. parentist eine vorhandene Referenz, mit der Einschränkungen für dasConstraintLayout-Composable selbst angegeben werden können.
Hier ist ein Beispiel für ein Composable mit 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) } ) } }
Dieser Code schränkt die Oberseite des Button mit einem Abstand von 16.dp auf das übergeordnete Element ein und den Text mit einem Abstand von 16.dp auf die Unterseite des Button.
Button und ein Text Composable, die in einem
ConstraintLayout aneinander gebunden sind.
Entkoppelte API
Im ConstraintLayout-Beispiel werden Einschränkungen inline mit einem Modifikator im Composable angegeben, auf das sie angewendet werden. Es gibt jedoch Situationen, in denen es besser ist, die Einschränkungen von den Layouts zu entkoppeln, auf die sie angewendet werden.
Sie können beispielsweise die Einschränkungen je nach Bildschirmkonfiguration ändern oder zwischen zwei Einschränkungssätzen animieren.
In solchen Fällen können Sie ConstraintLayout auf andere Weise verwenden:
- Übergeben Sie ein
ConstraintSetals Parameter anConstraintLayout. - Weisen Sie Composables mit dem
layoutIdModifikator Referenzen zu, die in derConstraintSeterstellt wurden.
@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) } } }
Wenn Sie die Einschränkungen ändern müssen, können Sie einfach ein anderes ConstraintSet übergeben.
ConstraintLayout-Konzepte
ConstraintLayout enthält Konzepte wie Richtlinien, Barrieren und Ketten, die bei der Positionierung von Elementen in Ihrem Composable helfen können.
Richtlinien
Richtlinien sind kleine visuelle Hilfen zum Entwerfen von Layouts. Composables können auf eine Richtlinie beschränkt werden. Richtlinien sind nützlich, um Elemente an einer
bestimmten dp oder percentage innerhalb des übergeordneten Composables zu positionieren.
Es gibt zwei verschiedene Arten von Richtlinien: vertikale und horizontale. Die beiden horizontalen sind top und bottom, die beiden vertikalen start und 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) }
Verwenden Sie createGuidelineFrom* mit dem erforderlichen Richtlinientyp, um eine Richtlinie zu erstellen. Dadurch wird eine Referenz erstellt, die im Block Modifier.constrainAs() verwendet werden kann.
Barrieren
Barrieren verweisen auf mehrere Composables, um eine virtuelle Richtlinie zu erstellen basierend auf dem extremsten Widget auf der angegebenen Seite.
Verwenden Sie createTopBarrier() (oder createBottomBarrier(), createEndBarrier(), createStartBarrier()) und geben Sie die Referenzen an, die die Barriere bilden sollen.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
Die Barriere kann dann in einem Modifier.constrainAs()-Block verwendet werden.
Ketten
Ketten bieten ein gruppenähnliches Verhalten auf einer einzelnen Achse (horizontal oder vertikal). Die andere Achse kann unabhängig eingeschränkt werden.
Verwenden Sie createVerticalChain oder
createHorizontalChain, um eine Kette zu erstellen:
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) } }
Die Kette kann dann im Block Modifier.constrainAs() verwendet werden.
Eine Kette kann mit verschiedenen ChainStyles konfiguriert werden, die festlegen, wie
mit dem Raum um ein Composable herum umgegangen werden soll, z. B.:
ChainStyle.Spread: Der Abstand wird gleichmäßig auf alle Composables verteilt, einschließlich des kostenlosen Raums vor dem ersten und nach dem letzten Composable.ChainStyle.SpreadInside: Der Abstand wird gleichmäßig auf alle Composables verteilt, ohne kostenlosen Raum vor dem ersten oder nach dem letzten Composable.ChainStyle.Packed: Der Abstand wird vor dem ersten und nach dem letzten Composable verteilt. Die Composables werden ohne Abstand zwischen ihnen zusammengepackt.