ConstraintLayout ist ein Layout, mit dem Sie Kompositionselemente relativ zu anderen Kompositionselementen auf dem Bildschirm platzieren können. Es ist eine Alternative zur Verwendung mehrerer verschachtelter Row-, Column-, Box- und anderer benutzerdefinierter Layoutelemente.
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. In Compose ist dies jedoch kein Problem, da tiefe Layouthierarchien effizient verarbeitet werden können. ConstraintLayout ist daher nicht so vorteilhaft.
Einführung in ConstraintLayout
Wenn Sie ConstraintLayout in Compose verwenden möchten, müssen Sie diese Abhängigkeit in Ihrer build.gradle hinzufügen (zusätzlich zur Compose-Einrichtung):
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
ConstraintLayout in Compose funktioniert mit einer DSL so:
- Erstellen Sie mit
createRefs()odercreateRefFor()Referenzen für jede zusammensetzbare Funktion imConstraintLayout. - Einschränkungen werden mit dem Modifikator
constrainAs()angegeben, der die Referenz als Parameter verwendet und es Ihnen ermöglicht, die Einschränkungen im Body-Lambda anzugeben. - Einschränkungen werden mit
linkTo()oder anderen hilfreichen Methoden angegeben. parentist eine vorhandene Referenz, mit der Einschränkungen für die komponierbare FunktionConstraintLayoutselbst angegeben werden können.
Hier ein Beispiel für eine zusammensetzbare Funktion, die ein ConstraintLayout verwendet:
@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 den oberen Rand des Button-Elements auf das übergeordnete Element mit einem Abstand von 16.dp und ein Text-Element auf den unteren Rand des Button-Elements ebenfalls mit einem Abstand von 16.dp ein.
Button- und ein Text-Composable, die in einem ConstraintLayout voneinander abhängig sind.
Entkoppelte API
Im Beispiel ConstraintLayout werden Einschränkungen inline mit einem Modifikator in der zusammensetzbaren Funktion angegeben, auf die 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.
Beispielsweise können Sie 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
ConstraintLayouteinenConstraintSetals Parameter. - Weisen Sie die in
ConstraintSeterstellten Referenzen mit dem ModifikatorlayoutIdComposables zu.
@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 eine andere ConstraintSet übergeben.
ConstraintLayout Konzepte
ConstraintLayout enthält Konzepte wie Richtlinien, Barrieren und Ketten, die Ihnen bei der Positionierung von Elementen in Ihrer zusammensetzbaren Funktion helfen können.
Richtlinien
Hilfslinien sind kleine visuelle Hilfen, die Sie beim Entwerfen von Layouts unterstützen. Composables können
auf eine Hilfslinie beschränkt werden. Hilfslinien sind nützlich, um Elemente an einer bestimmten dp oder percentage innerhalb der übergeordneten zusammensetzbaren Funktion zu positionieren.
Es gibt zwei verschiedene Arten von Hilfslinien: vertikale und horizontale. Die beiden horizontalen sind top und bottom, die beiden vertikalen sind 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 zum Erstellen einer Richtlinie createGuidelineFrom* mit dem erforderlichen Richtlinientyp. Dadurch wird eine Referenz erstellt, die im Block Modifier.constrainAs() verwendet werden kann.
Barrieren
Barrieren verweisen auf mehrere Composeables, um eine virtuelle Hilfslinie basierend auf dem extremsten Widget auf der angegebenen Seite zu erstellen.
Verwenden Sie zum Erstellen einer Barriere 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 davon eingeschränkt werden.
Verwenden Sie zum Erstellen einer Kette entweder createVerticalChain oder 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) } }
Die Kette kann dann im Modifier.constrainAs()-Block verwendet werden.
Eine Kette kann mit verschiedenen ChainStyles-Werten konfiguriert werden, die festlegen, wie der Platz um eine komponierbare Funktion herum behandelt wird, z. B.:
ChainStyle.Spread: Der Platz wird gleichmäßig auf alle Composables verteilt, einschließlich des leeren Platzes vor dem ersten und nach dem letzten Composable.ChainStyle.SpreadInside: Der Platz wird gleichmäßig auf alle Composables verteilt, ohne dass vor dem ersten oder nach dem letzten Composable leerer Platz bleibt.ChainStyle.Packed: Der Platz wird vor dem ersten und nach dem letzten Composable verteilt. Die Composables werden ohne Platz dazwischen zusammengepackt.