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 in Compose jedoch 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 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 der Button mit einem Abstand von 16.dp auf das übergeordnete Element ein und eine Text mit einem Abstand von 16.dp auf die Unterseite der Button.
Button und ein Text Composable, die in einem
ConstraintLayout aufeinander eingeschränkt 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 basierend auf der 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: vertikal und horizontal. 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 basierend auf dem äußersten Widget auf der angegebenen Seite eine virtuelle Richtlinie zu erstellen.
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 bestimmen, 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.