Flusslayouts in Compose

FlowRow und FlowColumn sind Composables, 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 werden mehrere Zeilen oder Spalten erstellt. Die Anzahl der Elemente in einer Zeile kann auch durch Festlegen von maxItemsInEachRow oder maxItemsInEachColumn gesteuert werden. Mit FlowRow und FlowColumn lassen sich oft responsive Layouts erstellen. Inhalte werden nicht abgeschnitten, wenn Elemente für eine Dimension zu groß sind. Mit einer Kombination aus maxItemsInEach* und Modifier.weight(weight) lassen sich Layouts erstellen, die bei Bedarf die Breite einer Zeile oder Spalte ausfüllen bzw. erweitern.

Das typische Beispiel ist für ein 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

Wenn Sie FlowRow oder FlowColumn verwenden möchten, erstellen Sie diese Composables und platzieren Sie die Elemente darin, die dem Standardablauf 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")
    }
}

Dieser Snippet führt zur oben gezeigten Benutzeroberfläche, wobei Elemente automatisch in die nächste Zeile fließen, 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 horizontal). Mit dem Parameter horizontalArrangement in FlowRow wird gesteuert, wie der kostenlose Speicherplatz zwischen Elementen verteilt wird.

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

Horizontale Anordnung auf 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, wobei der Standardwert Arrangement.Top ist.

Anordnung auf der Querachse

Die Querachse verläuft in die entgegengesetzte 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 sehen Sie Beispiele für das Festlegen verschiedener verticalArrangement für die Elemente für FlowRow:

Vertikale Anordnung auf FlowRow festgelegt

Ergebnis

Arrangement.Top (Default)

Anordnung der Container oben

Arrangement.Bottom

Anordnung des Containerbodens

Arrangement.Center

Anordnung der Container in der Mitte

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

Ausrichtung einzelner Elemente

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

Wenn Elemente in einem FlowRow beispielsweise 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 auf 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 einer Zeile oder Spalte

Mit den Parametern maxItemsInEachRow oder maxItemsInEachColumn wird die maximale Anzahl von Elementen auf der Hauptachse definiert, 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 sie aufgrund ihrer Größe 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

Artikelgewichte

Das Gewicht eines Artikels wird auf Grundlage seines Faktors und des verfügbaren Platzes in der Zeile, in der er platziert wurde, erhöht. Wichtig ist, dass sich FlowRow und Row darin unterscheiden, wie Gewichte zur Berechnung der Breite eines Elements verwendet werden. Für Rows basiert das Gewicht auf allen Artikeln in der Row. Bei FlowRow basiert die Gewichtung auf den Elementen in der Zeile, in der sich ein Element befindet, nicht auf allen Elementen im FlowRow-Container.

Wenn Sie beispielsweise vier Elemente haben, die alle auf einer Linie liegen und jeweils unterschiedliche Gewichte von 1f, 2f, 1f und 3f haben, beträgt das Gesamtgewicht 7f. Der verbleibende Platz in einer Zeile oder Spalte wird durch 7f geteilt. Anschließend wird die Breite der einzelnen Elemente mit weight * (remainingSpace / totalWeight) berechnet.

Sie können Modifier.weight und „max. Elemente“ mit FlowRow oder FlowColumn kombinieren, um ein rasterähnliches Layout zu erstellen. Diese Vorgehensweise 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 dargestellt:

Mit Flow-Zeile erstelltes Raster
Abbildung 2. FlowRow zum Erstellen eines Rasters verwenden

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

Wichtig: 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 ist:

Letztes Element in voller Größe im Raster
Abbildung 3: FlowRowRaster erstellen, bei dem das letzte Element die volle Breite einnimmt

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

Sie können auch ein abwechselndes Raster mit unterschiedlichen Artikelgrößen erstellen, in dem zwei Artikel jeweils die Hälfte der Breite und ein Artikel die volle Breite der nächsten Spalte einnehmen:

Wechselndes Raster mit Ablaufzeile
Abbildung 4: FlowRow mit abwechselnden Zeilengrößen

Dazu können Sie den folgenden Code verwenden:

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. Das unterscheidet sich von der Funktionsweise von Modifier.fillMaxWidth(fraction), wenn es auf Row oder Column angewendet wird. Row/Column-Elemente nehmen einen Prozentsatz der verbleibenden Breite ein und nicht die gesamte Breite des Containers.

Der folgende Code liefert beispielsweise unterschiedliche Ergebnisse, je nachdem, ob FlowRow oder 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 Bruchteil der gesamten Containerbreite.

Breite als Bruchteil mit Flow-Zeile

Row: Der mittlere Artikel nimmt 0,7 % der verbleibenden Row-Breite ein.

Breite als Bruchteil mit Zeile

fillMaxColumnWidth() und fillMaxRowHeight()

Wenn Sie entweder Modifier.fillMaxColumnWidth() oder Modifier.fillMaxRowHeight() auf ein Element in einem FlowColumn oder FlowRow anwenden, wird dafür gesorgt, dass Elemente in derselben Spalte oder Zeile dieselbe Breite oder Höhe wie das größte Element in der Spalte bzw. Zeile haben.

In diesem Beispiel wird FlowColumn verwendet, um die Liste der Android-Desserts anzuzeigen. Sie können den Unterschied in der Breite der einzelnen Elemente sehen, wenn Modifier.fillMaxColumnWidth() auf die Elemente angewendet wird und wenn nicht 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 (Umbrechen von Elementen)

Keine maximale Spaltenbreite für das automatische Anpassen festgelegt