Ablauflayouts in Compose

FlowRow und FlowColumn sind Elemente, die Row und Column ähneln, sich aber dadurch unterscheiden, dass Elemente in die nächste Zeile fließen, wenn im Container kein Platz mehr vorhanden ist. Dadurch werden mehrere Zeilen oder Spalten erstellt. Die Anzahl der Elemente in einer Zeile kann auch indem Sie maxItemsInEachRow oder maxItemsInEachColumn festlegen. Sie können häufig FlowRow und FlowColumn zum Erstellen responsiver Layouts – die Inhalte werden nicht ausgeschnitten wenn Artikel zu groß für eine Dimension sind, und wenn Sie eine Kombination maxItemsInEach* mit Modifier.weight(weight) kann Ihnen helfen, Layouts zu erstellen, die Breite einer Zeile oder Spalte bei Bedarf ausfüllen/erweitern können.

Das typische Beispiel zeigt einen Chip oder eine Filteroberfläche:

5 Chips in einer FlowRow, die den Überlauf in die nächste Zeile anzeigen, 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 zusammensetzbaren Funktionen und platzieren Sie die Elemente das dem Standardablauf folgen sollte:

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

Durch dieses Snippet wird die oben gezeigte Benutzeroberfläche angezeigt. Elemente werden automatisch wenn in der ersten Zeile kein Platz mehr ist.

Features des Ablauflayouts

Fluss-Layouts haben die folgenden Funktionen und Eigenschaften, die Sie verwenden können, um verschiedene Layouts in Ihrer App zu erstellen.

Anordnung der Hauptachse: horizontal oder vertikal

Die Hauptachse ist die Achse, auf der Elemente angeordnet werden (z. B. FlowRow, Elemente sind horizontal angeordnet. Das horizontalArrangement in FlowRow steuert, wie freier Speicherplatz auf die Elemente verteilt wird.

Die folgende Tabelle zeigt Beispiele für die Festlegung von horizontalArrangement für Elemente für FlowRow:

Horizontale Anordnung auf FlowRow festgelegt

Ergebnis

Arrangement.Start (Default)

Artikel nach Anfang angeordnet

Arrangement.SpaceBetween

Anordnung von Elementen mit Abstand dazwischen

Arrangement.Center

In der Mitte angeordnete Elemente

Arrangement.End

Elemente am Ende angeordnet

Arrangement.SpaceAround

Gegenstände in um sie herum angeordnetem Platz

Arrangement.spacedBy(8.dp)

Elemente mit einem bestimmten dp-Abstand

Für FlowColumn sind ähnliche Optionen mit verticalArrangement verfügbar, wobei Folgendes gilt: der Standardwert Arrangement.Top.

Querachsenanordnung

Die Querachse ist die Achse in der entgegengesetzten Richtung zur Hauptachse. In FlowRow ist das beispielsweise die vertikale Achse. Um zu ändern, wie der Gesamt- sind die Behälter in Querachsen angeordnet, verwenden Sie verticalArrangement für FlowRow und horizontalArrangement für FlowColumn.

In der folgenden Tabelle sind Beispiele für die Festlegung verschiedener verticalArrangement für die Elemente zu sehen:

Vertikale Anordnung auf FlowRow festgelegt

Ergebnis

Arrangement.Top (Default)

Anordnung des Containers oben

Arrangement.Bottom

Containerboden

Arrangement.Center

Container in der Mitte anordnen

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

Ausrichtung einzelner Elemente

Sie können einzelne Elemente innerhalb der Zeile mit unterschiedlichen Ausrichtungen positionieren. Dies unterscheidet sich von verticalArrangement und horizontalArrangement, indem die Elemente damit an der aktuellen Zeile ausgerichtet werden. Sie können das mit Modifier.align() tun.

Wenn beispielsweise Elemente in einem FlowRow unterschiedliche Höhen haben, wird in der Zeile Höhe des größten Elements und wendet Modifier.align(alignmentOption) auf den Wert Elemente:

Vertikale Ausrichtung auf FlowRow festgelegt

Ergebnis

Alignment.Top (Default)

Elemente, die oben ausgerichtet sind

Alignment.Bottom

Elemente, die unten ausgerichtet sind

Alignment.CenterVertically

Elemente mittig ausgerichtet

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

Maximale Anzahl der Elemente in Zeile oder Spalte

Die Parameter maxItemsInEachRow oder maxItemsInEachColumn definieren das Maximum Elemente in der Hauptachse in eine Linie zu lassen, bevor sie in die nächste verschoben werden. Die Der Standardwert ist Int.MAX_INT, womit so viele Elemente wie möglich zugelassen werden, solange sodass sie in die Linie passen.

Wenn Sie beispielsweise einen maxItemsInEachRow festlegen, wird das anfängliche Layout nur auf haben 3 Elemente:

Kein Maximalwert festgelegt

maxItemsInEachRow = 3

Kein Maximalwert für Ablaufzeile festgelegt Maximale Anzahl von Elementen in Ablaufzeile festgelegt

Elemente für Lazy Loading

ContextualFlowRow und ContextualFlowColumn sind eine spezielle Version von FlowRow und FlowColumn, mit der Sie den Inhalt Ihrer Flusszeile oder ‑spalte per Lazy Load laden können. Sie enthalten auch Informationen zur Position (Index, Zeilennummer und verfügbare Größe), z. B. ob sich das Element im ersten Zeile. Dies ist nützlich bei großen Datensätzen und wenn Sie Kontextinformationen benötigen, zu einem Artikel.

Der Parameter maxLines begrenzt die Anzahl der angezeigten Zeilen und der Parameter overflow gibt an, was angezeigt werden soll, wenn ein Artikelüberlauf erreicht haben, sodass Sie einen benutzerdefinierten Wert für expandIndicator oder collapseIndicator.

So können Sie beispielsweise die Schaltfläche „+ (Anzahl der verbleibenden Artikel)“ oder „Weniger anzeigen“ anzeigen lassen:

val totalCount = 40
var maxLines by remember {
    mutableStateOf(2)
}

val moreOrCollapseIndicator = @Composable { scope: ContextualFlowRowOverflowScope ->
    val remainingItems = totalCount - scope.shownItemCount
    ChipItem(if (remainingItems == 0) "Less" else "+$remainingItems", onClick = {
        if (remainingItems == 0) {
            maxLines = 2
        } else {
            maxLines += 5
        }
    })
}
ContextualFlowRow(
    modifier = Modifier
        .safeDrawingPadding()
        .fillMaxWidth(1f)
        .padding(16.dp)
        .wrapContentHeight(align = Alignment.Top)
        .verticalScroll(rememberScrollState()),
    verticalArrangement = Arrangement.spacedBy(4.dp),
    horizontalArrangement = Arrangement.spacedBy(8.dp),
    maxLines = maxLines,
    overflow = ContextualFlowRowOverflow.expandOrCollapseIndicator(
        minRowsToShowCollapse = 4,
        expandIndicator = moreOrCollapseIndicator,
        collapseIndicator = moreOrCollapseIndicator
    ),
    itemCount = totalCount
) { index ->
    ChipItem("Item $index")
}

Beispiel für kontextbezogene Ablaufzeilen
Abbildung 2: Beispiel für ContextualFlowRow

Artikelgewichte

Die Gewichtung vergrößert ein Element basierend auf seinem Faktor und dem verfügbaren Platz auf der Linie. in den einsortiert wurde. Ein wichtiger Unterschied zwischen FlowRow und Row besteht darin, wie Gewichte zur Berechnung der Breite eines Elements verwendet werden. Gewicht (Rows) basiert auf allen Artikeln in Row. Bei FlowRow basiert das Gewicht auf dem Elemente der Werbebuchung, in der ein Element platziert wird, nicht alle Elemente im FlowRow-Container.

Wenn Sie beispielsweise vier Artikel haben, die alle auf einer Linie liegen, und die 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. Dann ist jede Elementbreite mit folgender Formel berechnet: weight * (remainingSpace / totalWeight).

Sie können eine Kombination aus Modifier.weight und maximal zulässigen Elementen mit FlowRow oder FlowColumn, um ein rasterähnliches Layout zu erstellen. Dieser Ansatz eignet sich zum Erstellen responsiver Layouts, die sich an die Größe Ihres Geräts anpassen.

Es gibt verschiedene Beispiele dafür, was Sie mit Gewichtungen erreichen können. Eins Ein Beispiel ist ein Raster, in dem Elemente die gleiche Größe haben, wie unten dargestellt:

Raster mit Flusszeile erstellt
Abbildung 3 Raster mit FlowRow erstellen

So erstellen Sie ein Raster gleicher Artikelgröße:

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 dieses 10-mal statt 9-mal wiederholen, Das letzte Element nimmt die gesamte letzte Spalte ein, als Gesamtgewichtung für die gesamte Zeile ist 1f:

Letztes Element in Originalgröße im Raster
Abbildung 4: Mit FlowRow ein Raster erstellen, bei dem das letzte Element die volle Breite einnimmt

Du kannst Gewichte mit anderen Modifiers-Elementen kombinieren, z. B. Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) oder Modifier.fillMaxWidth(fraction) Diese Modifikatoren wirken alle in Verbindung mit Responsive Größenanpassung für Artikel innerhalb eines FlowRow (oder FlowColumn) ist möglich.

Sie können auch ein abwechselndes Raster mit unterschiedlichen Elementgrößen erstellen, in dem zwei Elemente jeweils halb so breit und ein Element nimmt die volle Breite des nächsten ein Spalte:

Sich abwechselndes Raster mit Ablaufzeile
Abbildung 5: FlowRow mit abwechselnder Zeilengröße

Das geht mit dem folgenden 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))
        }
    }
}

Teilgrößenanpassung

Mit Modifier.fillMaxWidth(fraction) können Sie die Größe des Containers angeben, den ein Artikel 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, anstatt die gesamte Breite des Containers.

Der folgende Code führt beispielsweise zu anderen Ergebnissen bei der Verwendung von FlowRow. gegen Row:

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 einem 0,7-Anteil der gesamten Containerbreite.

Bruchteilbreite mit Flusszeile

Row: Das mittlere Element nimmt 0,7 % der verbleibenden Breite von Row ein.

Bruchbreite mit Zeile

fillMaxColumnWidth() und fillMaxRowHeight()

Sie wenden entweder Modifier.fillMaxColumnWidth() oder Modifier.fillMaxRowHeight() auf einen Artikel in einem FlowColumn oder FlowRow dass Elemente in derselben Spalte oder Zeile dieselbe Breite oder Höhe einnehmen wie das größte Element in der Spalte/Zeile.

In diesem Beispiel wird FlowColumn beispielsweise verwendet, um die Liste der Android-Desserts anzuzeigen. Sie sehen den Unterschied bei der Breite der einzelnen Elemente, wenn Modifier.fillMaxColumnWidth() wird auf die Elemente angewendet, im Vergleich dazu, wenn dies nicht der Fall ist und die Elemente verpacken.

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

Es wurden keine Änderungen an der Breite festgelegt (Elemente werden umgebrochen)

Es wurde keine maximale Spaltenbreite für die Füllung festgelegt.