ConstraintLayout in Compose

ConstraintLayout ist ein Layout, mit dem Sie Elemente relativ zu anderen Elementen auf dem Bildschirm platzieren können. Es ist eine Alternative zur Verwendung mehrerer verschachtelter Row-, Column-, Box- und anderer benutzerdefinierter Layoutelemente. ConstraintLayout ist nützlich, wenn Sie größere Layouts mit komplexeren Ausrichtungsanforderungen implementieren.

Erwägen Sie die Verwendung von ConstraintLayout in den folgenden Szenarien:

  • Vermeiden Sie das Verschachteln mehrerer Column- und Row-Tags, um Elemente auf dem Bildschirm zu positionieren und die Lesbarkeit des Codes zu verbessern.
  • Damit lassen sich Elemente relativ zu anderen Elementen oder anhand von Richtlinien, Barrieren oder Ketten positionieren.

Im Ansichtssystem war ConstraintLayout die empfohlene Methode zum Erstellen großer und komplexer Layouts, da eine flache Ansichtshierarchie die Leistung verbesserte. In Compose ist das jedoch kein Problem, da hier tiefe Layouthierarchien effizient verarbeitet werden können.

Einführung in 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:1.0.1"

ConstraintLayout in Compose funktioniert mit einer DSL so:

  • Erstellen Sie mit createRefs() oder createRefFor() Verweise für jedes Composeable in der ConstraintLayout.
  • Einschränkungen werden mit dem Modifikator constrainAs() angegeben. Dieser nimmt die Referenz als Parameter entgegen und ermöglicht es, die Einschränkungen im Lambda-Body anzugeben.
  • Einschränkungen werden mit linkTo() oder anderen hilfreichen Methoden angegeben.
  • parent ist ein vorhandener Verweis, mit dem Einschränkungen gegenüber der zusammensetzbaren Funktion ConstraintLayout selbst angegeben werden können.

Hier ein Beispiel für ein ConstraintLayout-Element in einem Composeable:

@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)
            }
        )
    }
}

Mit diesem Code wird die Oberseite des Button mit einer Marge von 16.dp an das übergeordnete Element gebunden und eine Text am unteren Rand des Button mit einer Marge von 16.dp.

Zeigt eine Schaltfläche und ein Textelement in einem ConstraintLayout-Element an

Entkoppelte API

Im ConstraintLayout-Beispiel werden die Einschränkungen inline mit einem Modifikator im Kompositionen-Element 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 sich beziehen. So können Sie beispielsweise die Einschränkungen basierend auf der Bildschirmkonfiguration ändern oder zwischen zwei Einschränkungen animieren.

In solchen Fällen können Sie ConstraintLayout auf andere Weise verwenden:

  1. Übergeben Sie ConstraintSet als Parameter an ConstraintLayout.
  2. Weisen Sie mit dem Modifikator layoutId Verweise zu, die im 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öchten, können Sie einfach eine andere ConstraintSet übergeben.

ConstraintLayout Konzepte

ConstraintLayout enthält Konzepte wie Richtlinien, Barrieren und Ketten, die Ihnen bei der Platzierung von Elementen in Ihrem Composable helfen können.

Richtlinien

Richtlinien sind kleine visuelle Hilfsmittel beim Entwerfen von Layouts. Composables können auf eine Richtlinie beschränkt werden. Richtlinien sind hilfreich, um Elemente an einem bestimmten dp oder percentage innerhalb der übergeordneten zusammensetzbaren Funktion zu positionieren.

Es gibt zwei Arten von Richtlinien: vertikale und horizontale. Die beiden horizontalen sind top und bottom und 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 createGuidelineFrom* mit der erforderlichen Art der Richtlinie, um eine Richtlinie zu erstellen. Dadurch wird ein Verweis erstellt, der im Block Modifier.constrainAs() verwendet werden kann.

Barrieren

Grenzen beziehen sich auf mehrere Elemente, um eine virtuelle Leitlinie basierend auf dem äußersten Widget auf der angegebenen Seite zu erstellen.

Verwende zum Erstellen einer Hürde createTopBarrier() (oder createBottomBarrier(), createEndBarrier(), createStartBarrier()) und gib die Referenzen an, die die Hürde bilden sollen.

ConstraintLayout {
    val constraintSet = ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        val topBarrier = createTopBarrier(button, text)
    }
}

Die Hürde kann dann in einem Modifier.constrainAs()-Block verwendet werden.

Ketten

Ketten bieten ein gruppenähnliches Verhalten in einer einzigen 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 konfiguriert werden, die festlegen, wie mit dem Raum um ein Composeable umgegangen werden soll, z. B.:

  • ChainStyle.Spread: Der Platz wird gleichmäßig auf alle Elemente verteilt, einschließlich des kostenlosen Platzes vor dem ersten und nach dem letzten Element.
  • ChainStyle.SpreadInside: Der Raum wird gleichmäßig auf alle zusammensetzbaren Funktionen verteilt, ohne dass vor der ersten zusammensetzbaren Funktion oder nach der letzten zusammensetzbaren Funktion Platz hat.
  • ChainStyle.Packed: Der Platz wird vor dem ersten und nach dem letzten Composeable verteilt. Die Composeables werden ohne Leerraum aneinandergereiht.

Weitere Informationen

Weitere Informationen zu ConstraintLayout in Compose finden Sie in den APIs in Aktion in den Compose-Beispielen mit ConstraintLayout.