Flusslayouts in Compose

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

Ein typisches Beispiel ist eine Chip- oder Filter-UI:

5 Chips in einer FlowRow, die in die nächste Zeile umbrechen, 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")
    }
}

Dieses Snippet führt zu der oben gezeigten Benutzeroberfläche, wobei Elemente automatisch in die nächste Zeile verschoben werden, wenn in der ersten Zeile kein Platz mehr ist.

Funktionen des Flusslayouts

Flusslayouts 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. In FlowRow werden Elemente beispielsweise horizontal angeordnet. Der Parameter horizontalArrangement in FlowRow steuert, wie der verfügbare Platz zwischen den Elementen verteilt wird.

Die folgende Tabelle enthält Beispiele für das Festlegen von horizontalArrangement für Elemente für FlowRow:

Horizontale Anordnung auf FlowRow festgelegt

Ergebnis

Arrangement.Start (Default)

Elemente mit „start“ angeordnet

Arrangement.SpaceBetween

Anordnung der Elemente mit Abstand dazwischen

Arrangement.Center

In der Mitte angeordnete Artikel

Arrangement.End

Am Ende angeordnete Elemente

Arrangement.SpaceAround

Elemente mit Abstand dazwischen

Arrangement.spacedBy(8.dp)

Elemente mit einem bestimmten Abstand in dp

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

Anordnung der Querachse

Die Querachse ist die Achse in der entgegengesetzten Richtung zur Hauptachse. In FlowRow ist dies beispielsweise die vertikale Achse. Wenn Sie die Anordnung des gesamten Inhalts im Container auf der Querachse ändern möchten, 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 von FlowRow:

Vertikale Anordnung auf FlowRow festgelegt

Ergebnis

Arrangement.Top (Default)

Anordnung von Containern von oben

Arrangement.Bottom

Anordnung am Containerboden

Arrangement.Center

Container mittig anordnen

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 innerhalb der Zeile mit unterschiedlichen Ausrichtungen positionieren. Dies unterscheidet sich von verticalArrangement und horizontalArrangement, da Elemente innerhalb der aktuellen Zeile ausgerichtet werden. Sie können dies mit Modifier.align() anwenden.

Wenn beispielsweise Elemente in einem FlowRow unterschiedlich hoch sind, wird die Höhe des größten Elements für die Zeile verwendet und Modifier.align(alignmentOption) auf die Elemente angewendet:

Vertikale Ausrichtung auf FlowRow festgelegt

Ergebnis

Alignment.Top (Default)

Elemente am oberen Rand ausgerichtet

Alignment.Bottom

Am unteren Rand ausgerichtete Elemente

Alignment.CenterVertically

Elemente wurden zentriert

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, solange sie aufgrund ihrer Größe in die Zeile passen.

Wenn Sie beispielsweise maxItemsInEachRow festlegen, wird das anfängliche Layout auf nur drei Elemente beschränkt:

Kein Maximum festgelegt

maxItemsInEachRow = 3

Kein Maximum für die Flusszeile festgelegt Maximale Anzahl von Elementen in der Flusszeile festgelegt

Artikelgewichtungen

Mit „weight“ wird ein Element basierend auf seinem Faktor und dem verfügbaren Platz in der Zeile, in der es platziert wurde, vergrößert. Wichtig ist, dass es einen Unterschied zwischen FlowRow und Row gibt, wenn es darum geht, wie Gewichtungen zur Berechnung der Breite eines Elements verwendet werden. Bei Rows basiert die Gewichtung auf allen Elementen in Row. Bei FlowRow basiert die Gewichtung auf den Elementen in der Zeile, in der ein Element platziert ist, nicht auf allen Elementen im FlowRow-Container.

Wenn Sie beispielsweise vier Elemente haben, die alle auf einer Linie liegen, mit jeweils unterschiedlichen Gewichtungen von 1f, 2f, 1f und 3f, beträgt die Gesamtgewichtung 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 eine Kombination aus Modifier.weight und der maximalen 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.

Hier sind einige Beispiele dafür, was Sie mit Gewichtungen erreichen können. Ein Beispiel ist ein Raster, in dem die Elemente gleich groß sind, wie unten dargestellt:

Raster mit Flusszeile erstellt
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)
    }
}

Wenn Sie ein weiteres Element hinzufügen und es zehnmal statt neunmal 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 Gewichtungen mit anderen Modifiers wie Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) oder Modifier.fillMaxWidth(fraction) kombinieren. Diese Modifikatoren ermöglichen zusammen die responsive Größenanpassung von Elementen innerhalb einer FlowRow (oder FlowColumn).

Sie können auch ein abwechselndes Raster mit verschiedenen Elementgrößen erstellen, bei dem zwei Elemente jeweils die Hälfte der Breite und ein Element die gesamte Breite der nächsten Spalte einnehmen:

Abwechselndes Raster mit Flusszeile
Abbildung 4: FlowRow mit abwechselnden Zeilengrößen

Hierfür können Sie beispielsweise 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, da Row/Column-Elemente einen Prozentsatz der verbleibenden Breite einnehmen, nicht die gesamte Breite des Containers.

Der folgende Code liefert beispielsweise unterschiedliche Ergebnisse, wenn 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 Anteil der gesamten Containerbreite.

Bruchbreite mit Flusszeile

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

Breite als Bruch mit Zeile

fillMaxColumnWidth() und fillMaxRowHeight()

Wenn Sie Modifier.fillMaxColumnWidth() oder Modifier.fillMaxRowHeight() auf ein Element in einem 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 können den Unterschied in der Breite der einzelnen Elemente sehen, wenn Modifier.fillMaxColumnWidth() auf die Elemente angewendet wird, im Vergleich dazu, wenn dies nicht der Fall ist und die Elemente umbrochen 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 Änderungen der Breite festgelegt (Elemente werden umbrochen)

Keine maximale Spaltenbreite für das Ausfüllen festgelegt