Flusslayouts in Compose

FlowRow und FlowColumn sind zusammensetzbare Funktionen, die Row und Column ähneln, sich aber dadurch unterscheiden, dass Elemente in die nächste Zeile fließen, wenn der Container keinen Platz mehr bietet. Dadurch entstehen mehrere Zeilen oder Spalten. Die Anzahl der Elemente in einer Zeile kann auch durch Festlegen von maxItemsInEachRow oder maxItemsInEachColumn gesteuert werden. Sie können FlowRow und FlowColumn oft verwenden, um responsive Layouts zu erstellen. Inhalte werden nicht abgeschnitten, wenn Elemente zu groß für eine Dimension sind. Durch die Kombination von maxItemsInEach* mit Modifier.weight(weight) lassen sich Layouts erstellen, die die Breite einer Zeile oder Spalte bei Bedarf ausfüllen oder erweitern.

Das typische Beispiel ist eine Chip- oder Filter-UI:

Fünf Chips in einer FlowRow, die den Überlauf in die nächste Zeile zeigen, wenn kein Platz mehr verfügbar ist.
Abbildung 1. Beispiel für FlowRow

Grundlegende Nutzung

Um FlowRow oder FlowColumn zu verwenden, erstellen Sie diese zusammensetzbaren Funktionen und platzieren Sie die Elemente darin, die dem Standardfluss folgen sollen:

@Composable
private fun FlowRowSimpleUsageExample() {
    FlowRow(modifier = Modifier.padding(8.dp)) {
        ChipItem("Price: High to Low")
        ChipItem("Avg rating: 4+")
        ChipItem("Free breakfast")
        ChipItem("Free cancellation")
        ChipItem("£50 pn")
    }
}

Dieses Snippet führt zu der oben gezeigten UI. Elemente fließen automatisch in die nächste Zeile, wenn in der ersten Zeile kein Platz mehr ist.

Funktionen des Flow-Layouts

Flow-Layouts haben die folgenden Funktionen und Eigenschaften, mit denen Sie verschiedene Layouts in Ihrer App erstellen können.

Anordnung der Hauptachse: horizontale oder vertikale Anordnung

Die Hauptachse ist die Achse, auf der Elemente angeordnet werden (z. B. in FlowRow werden Elemente horizontal angeordnet). Der Parameter horizontalArrangement in FlowRow steuert, wie der kostenlose Platz zwischen den Elementen verteilt wird.

In der folgenden Tabelle finden Sie Beispiele für das Festlegen von horizontalArrangement für Elemente in FlowRow:

Horizontale Anordnung für FlowRow festgelegt

Ergebnis

Arrangement.Start (Default)

Artikel mit Startdatum

Arrangement.SpaceBetween

Anordnung von Elementen mit Zwischenräumen

Arrangement.Center

Artikel in der Mitte angeordnet

Arrangement.End

Elemente am Ende angeordnet

Arrangement.SpaceAround

Elemente mit Leerraum um sie herum

Arrangement.spacedBy(8.dp)

Elemente, die durch eine bestimmte Anzahl von DPs getrennt sind

Für FlowColumn sind ähnliche Optionen mit verticalArrangement verfügbar. Die Standardeinstellung ist Arrangement.Top.

Anordnung der Querachse

Die Querachse ist die Achse in der entgegengesetzten Richtung der Hauptachse. In FlowRow ist das beispielsweise die vertikale Achse. Wenn Sie ändern möchten, wie die Inhalte im Container auf der Querachse angeordnet werden, verwenden Sie verticalArrangement für FlowRow und horizontalArrangement für FlowColumn.

In der folgenden Tabelle finden Sie Beispiele für das Festlegen verschiedener verticalArrangement für die Elemente in FlowRow:

Vertikale Anordnung für FlowRow festgelegt

Ergebnis

Arrangement.Top (Default)

Anordnung der Container oben

Arrangement.Bottom

Anordnung des Containerbodens

Arrangement.Center

Anordnung der Containerzentren

Für FlowColumn sind ähnliche Optionen mit horizontalArrangement verfügbar. Die Standardanordnung der Querachse ist Arrangement.Start.

Ausrichtung einzelner Elemente

Möglicherweise möchten Sie einzelne Elemente in der Zeile mit unterschiedlichen Ausrichtungen positionieren. Dies unterscheidet sich von verticalArrangement und horizontalArrangement, da Elemente in der aktuellen Zeile ausgerichtet werden. Sie können dies mit Modifier.align() anwenden.

Wenn beispielsweise Elemente in einer FlowRow unterschiedliche Höhen haben, wird die Höhe der Zeile an das größte Element angepasst und Modifier.align(alignmentOption) auf die Elemente angewendet:

Vertikale Ausrichtung für FlowRow festgelegt

Ergebnis

Alignment.Top (Default)

Elemente am oberen Rand ausgerichtet

Alignment.Bottom

Elemente am unteren Rand ausgerichtet

Alignment.CenterVertically

Elemente, die mittig ausgerichtet sind

Für FlowColumn sind ähnliche Optionen verfügbar. Die Standardausrichtung ist Alignment.Start.

Maximale Anzahl von Elementen in Zeile oder Spalte

Die Parameter maxItemsInEachRow oder maxItemsInEachColumn definieren die maximale Anzahl von Elementen auf der Hauptachse, die in einer Zeile zulässig sind, bevor sie in die nächste Zeile umgebrochen werden. Der Standardwert ist Int.MAX_INT. Damit sind so viele Elemente wie möglich zulässig, sofern ihre Größen in die Zeile passen.

Wenn Sie beispielsweise maxItemsInEachRow festlegen, enthält das ursprüngliche Layout nur drei Elemente:

Kein Maximum festgelegt

maxItemsInEachRow = 3

Kein Maximum für Flow-Zeile festgelegt Maximale Anzahl von Elementen in der Ablaufzeile

Elementgewichte

Das Gewicht vergrößert ein Element basierend auf seinem Faktor und dem verfügbaren Platz in der Zeile, in der es platziert wurde. Es gibt einen wichtigen Unterschied zwischen FlowRow und Row in Bezug darauf, wie Gewichte zur Berechnung der Breite eines Elements verwendet werden. Bei Rows basiert das Gewicht auf allen Elementen in der Row. Bei FlowRow basiert das Gewicht auf den Elementen in der Zeile, in der ein Element platziert wird, nicht auf allen Elementen im FlowRow Container.

Wenn Sie beispielsweise vier Elemente haben, die alle in einer Zeile liegen, und die Gewichte 1f, 2f, 1f und 3f sind, beträgt das Gesamtgewicht 7f. Der verbleibende Platz in einer Zeile oder Spalte wird durch 7f geteilt. Anschließend wird die Breite jedes Elements mit folgender Formel berechnet: weight * (remainingSpace / totalWeight).

Sie können eine Kombination aus Modifier.weight und maximaler Anzahl von Elementen mit FlowRow oder FlowColumn verwenden, um ein rasterähnliches Layout zu erstellen. Dieser Ansatz ist nützlich, um responsive Layouts zu erstellen, die sich an die Größe Ihres Geräts anpassen.

Es gibt verschiedene Beispiele dafür, was Sie mit Gewichten erreichen können. Ein Beispiel ist ein Raster, in dem die Elemente gleich groß sind, wie unten gezeigt:

Mit Flow-Zeile erstelltes Raster
Abbildung 2. Mit FlowRow ein Raster erstellen

So erstellen Sie ein Raster mit gleich großen Elementen:

val rows = 3
val columns = 3
FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = rows
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .weight(1f)
        .clip(RoundedCornerShape(8.dp))
        .background(MaterialColors.Blue200)
    repeat(rows * columns) {
        Spacer(modifier = itemModifier)
    }
}

Wenn Sie ein weiteres Element hinzufügen und es 10 Mal anstelle von 9 Mal wiederholen, nimmt das letzte Element die gesamte letzte Spalte ein, da das Gesamtgewicht für die gesamte Zeile 1f beträgt:

Letztes Element in voller Größe im Raster
Abbildung 3. Mit FlowRow ein Raster erstellen, bei dem das letzte Element die volle Breite einnimmt

Sie können Gewichte mit anderen Modifiers wie Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio), oder Modifier.fillMaxWidth(fraction) kombinieren. Diese Modifikatoren arbeiten zusammen, um eine responsive Größenanpassung von Elementen in einer FlowRow (oder FlowColumn) zu ermöglichen.

Sie können auch ein abwechselndes Raster mit unterschiedlich großen Elementen erstellen, bei dem zwei Elemente jeweils die Hälfte der Breite einnehmen und ein Element die volle Breite der nächsten Spalte einnimmt:

Abwechselndes Raster mit Flow-Zeile
Abbildung 4. FlowRow mit abwechselnden Zeilengrößen

Das erreichen Sie mit folgendem Code:

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 2
) {
    val itemModifier = Modifier
        .padding(4.dp)
        .height(80.dp)
        .clip(RoundedCornerShape(8.dp))
        .background(Color.Blue)
    repeat(6) { item ->
        // if the item is the third item, don't use weight modifier, but rather fillMaxWidth
        if ((item + 1) % 3 == 0) {
            Spacer(modifier = itemModifier.fillMaxWidth())
        } else {
            Spacer(modifier = itemModifier.weight(0.5f))
        }
    }
}

Größenanpassung nach Bruchwerten

Mit Modifier.fillMaxWidth(fraction) können Sie die Größe des Containers angeben, den ein Element einnehmen soll. Dies unterscheidet sich von der Funktionsweise von Modifier.fillMaxWidth(fraction), wenn es auf Row oder Column angewendet wird. In diesem Fall nehmen Row/Column-Elemente einen Prozentsatz der verbleibenden Breite ein, nicht die gesamte Breite des Containers.

Der folgende Code führt beispielsweise zu unterschiedlichen Ergebnissen, wenn FlowRow im Vergleich zu Row verwendet wird:

FlowRow(
    modifier = Modifier.padding(4.dp),
    horizontalArrangement = Arrangement.spacedBy(4.dp),
    maxItemsInEachRow = 3
) {
    val itemModifier = Modifier
        .clip(RoundedCornerShape(8.dp))
    Box(
        modifier = itemModifier
            .height(200.dp)
            .width(60.dp)
            .background(Color.Red)
    )
    Box(
        modifier = itemModifier
            .height(200.dp)
            .fillMaxWidth(0.7f)
            .background(Color.Blue)
    )
    Box(
        modifier = itemModifier
            .height(200.dp)
            .weight(1f)
            .background(Color.Magenta)
    )
}

FlowRow: Mittleres Element mit 0,7 des Bruchwerts der gesamten Containerbreite.

Breite als Bruchteil mit Flow-Zeile

Row: Mittleres Element, das 0,7 % der verbleibenden Row-Breite einnimmt.

Breite als Bruchteil mit Zeile

fillMaxColumnWidth() und fillMaxRowHeight()

Wenn Sie Modifier.fillMaxColumnWidth() oder Modifier.fillMaxRowHeight() auf ein Element in einer FlowColumn oder FlowRow anwenden, nehmen Elemente in derselben Spalte oder Zeile dieselbe Breite oder Höhe wie das größte Element in der Spalte/Zeile ein.

In diesem Beispiel wird FlowColumn verwendet, um die Liste der Android-Desserts anzuzeigen. Sie sehen den Unterschied in der Breite der einzelnen Elemente, wenn Modifier.fillMaxColumnWidth() auf die Elemente angewendet wird und wenn dies nicht der Fall ist und die Elemente umgebrochen werden.

FlowColumn(
    Modifier
        .padding(20.dp)
        .fillMaxHeight()
        .fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    verticalArrangement = Arrangement.spacedBy(8.dp),
    maxItemsInEachColumn = 5,
) {
    repeat(listDesserts.size) {
        Box(
            Modifier
                .fillMaxColumnWidth()
                .border(1.dp, Color.DarkGray, RoundedCornerShape(8.dp))
                .padding(8.dp)
        ) {

            Text(
                text = listDesserts[it],
                fontSize = 18.sp,
                modifier = Modifier.padding(3.dp)
            )
        }
    }
}

Modifier.fillMaxColumnWidth() auf jedes Element angewendet

fillMaxColumnWidth

Keine Breitenänderungen festgelegt (Elemente werden umgebrochen)

Keine maximale Spaltenbreite für das automatische Anpassen festgelegt