ConstraintLayout in Compose

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. ConstraintLayout ist nützlich, wenn Sie größere Layouts mit komplexeren Ausrichtungsanforderungen implementieren.

In den folgenden Szenarien kann es sinnvoll sein, ConstraintLayout zu verwenden:

  • Um die Lesbarkeit des Codes zu verbessern, sollten Sie nicht mehrere Column- und Row-Tags verschachteln, um Elemente auf dem Bildschirm zu positionieren.
  • Sie können Composables relativ zu anderen Composables oder basierend auf Richtlinien, Barrieren oder Ketten positionieren.

Im View-System war ConstraintLayout die empfohlene Methode zum Erstellen großer und komplexer Layouts, da eine flache View-Hierarchie besser für die Leistung war als verschachtelte Views. In Compose ist das jedoch kein Problem, da hier auch tiefe Layoutstrukturen effizient verarbeitet werden können.

Mit ConstraintLayout beginnen

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:1.0.1"

ConstraintLayout in Compose funktioniert so:

  • Erstellen Sie mit createRefs() oder createRefFor() Referenzen für jede Composable in ConstraintLayout.
  • Einschränkungen werden mit dem Modifikator constrainAs() angegeben, der die Referenz als Parameter verwendet und mit dem Sie die Einschränkungen im Lambda-Ausdruck des Texts angeben können.
  • Einschränkungen werden mit linkTo() oder anderen hilfreichen Methoden angegeben.
  • parent ist eine vorhandene Referenz, mit der Einschränkungen für das zusammensetzbare Element ConstraintLayout angegeben werden können.

Hier ein Beispiel für eine zusammensetzbare Funktion, die eine 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 die Oberkante von Button auf das übergeordnete Element mit einem Rand von 16.dp und die Unterkante von Button ebenfalls mit einem Rand von 16.dp ein.Text

Zeigt eine Schaltfläche und ein Textelement an, die in einem ConstraintLayout angeordnet sind

Entkoppelte API

Im Beispiel ConstraintLayout werden Einschränkungen inline mit einem Modifier 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:

  1. Übergeben Sie ein ConstraintSet als Parameter an ConstraintLayout.
  2. Weisen Sie Composables mit dem Modifier layoutId Referenzen zu, die in ConstraintSet erstellt 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 beim Positionieren von Elementen in Ihrem Composable helfen können.

Richtlinien

Richtlinien sind kleine visuelle Hilfsmittel, mit denen sich Layouts gestalten lassen. Composables können an eine Richtlinie gebunden werden. Mit Richtlinien lassen sich Elemente an einer bestimmten dp oder percentage innerhalb der übergeordneten Composable-Funktion positionieren.

Es gibt zwei verschiedene Arten von Hilfslinien: vertikale und horizontale. Die beiden horizontalen sind top und bottom und 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*, um eine Richtlinie zu erstellen. Geben Sie dabei den erforderlichen Richtlinientyp an. Dadurch wird eine Referenz erstellt, die im Modifier.constrainAs()-Block verwendet werden kann.

Barrieren

Barriers verweisen auf mehrere Composables, um eine virtuelle Richtlinie basierend auf dem äußersten Widget auf der angegebenen Seite zu erstellen.

Verwenden Sie zum Erstellen einer Barriere createTopBarrier() (oder createBottomBarrier(), createEndBarrier(), createStartBarrier()) und geben Sie die Referenzen an, aus denen die Barriere bestehen soll.

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.

Chains

Ketten bieten gruppenähnliches Verhalten auf einer einzelnen Achse (horizontal oder vertikal). Die andere Achse kann unabhängig 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 konfiguriert werden, die festlegen, wie mit dem Leerraum um eine zusammensetzbare Funktion umgegangen werden soll, z. B.:

  • ChainStyle.Spread: Der Leerraum wird gleichmäßig auf alle Composables verteilt, einschließlich des Leerraums 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 kostenloser Platz vorhanden ist.
  • ChainStyle.Packed: Der Leerraum wird vor dem ersten und nach dem letzten Composable verteilt. Die Composables werden ohne Leerraum dazwischen zusammengefasst.

Weitere Informationen

Compose-Beispiele, in denen ConstraintLayout verwendet wirdConstraintLayout