Układy przepływu w Compose

FlowRowFlowColumn to funkcje kompozycyjne podobne do RowColumn, ale różniące się tym, że elementy przechodzą do następnego wiersza, gdy w kontenerze zabraknie miejsca. Spowoduje to utworzenie wielu wierszy lub kolumn. Liczbę elementów w wierszu można też kontrolować, ustawiając maxItemsInEachRow lub maxItemsInEachColumn. Elementów FlowRowFlowColumn możesz często używać do tworzenia układów elastycznych – zawartość nie zostanie obcięta, jeśli elementy będą zbyt duże w jednym wymiarze, a połączenie maxItemsInEach*Modifier.weight(weight) może pomóc w tworzeniu układów, które w razie potrzeby wypełniają lub rozszerzają szerokość wiersza lub kolumny.

Typowy przykład to element lub interfejs filtrowania:

5 elementów w FlowRow, pokazujących przepełnienie do następnego wiersza, gdy nie ma więcej miejsca.
Rysunek 1. Przykład FlowRow

Podstawowe użycie

Aby użyć funkcji FlowRow lub FlowColumn, utwórz te funkcje kompozycyjne i umieść w nich elementy, które powinny być zgodne ze standardowym przepływem:

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

Ten fragment kodu powoduje wyświetlenie interfejsu pokazanego powyżej, w którym elementy automatycznie przechodzą do następnego wiersza, gdy w pierwszym wierszu nie ma już miejsca.

Funkcje układu przepływu

Układy przepływu mają te funkcje i właściwości, których możesz używać do tworzenia różnych układów w aplikacji.

Rozmieszczenie wzdłuż osi głównej: rozmieszczenie poziome lub pionowe

Główna oś to oś, wzdłuż której rozmieszczone są elementy (np. w przypadku FlowRow elementy są rozmieszczone poziomo). Parametr horizontalArrangementFlowRow określa sposób rozdzielania wolnego miejsca między elementami.

W tabeli poniżej znajdziesz przykłady ustawiania wartości horizontalArrangement w przypadku elementów FlowRow:

Ustawiono układ poziomy na FlowRow

Wynik

Arrangement.Start (Default)

Elementy uporządkowane od początku

Arrangement.SpaceBetween

Rozmieszczenie elementów z odstępami

Arrangement.Center

Elementy ułożone na środku

Arrangement.End

Elementy ułożone na końcu

Arrangement.SpaceAround

Elementy rozmieszczone z wolną przestrzenią wokół nich

Arrangement.spacedBy(8.dp)

Elementy oddalone od siebie o określoną liczbę pikseli

W przypadku parametru FlowColumn dostępne są podobne opcje z parametrem verticalArrangement, przy czym domyślna wartość to Arrangement.Top.

Układ osi poprzecznych

Oś poprzeczna jest osią w kierunku przeciwnym do osi głównej. Na przykład w przypadku FlowRow jest to oś pionowa. Aby zmienić sposób rozmieszczenia ogólnej zawartości w kontenerze wzdłuż osi poprzecznej, użyj verticalArrangement w przypadku FlowRow i horizontalArrangement w przypadku FlowColumn.

W tabeli poniżej znajdziesz przykłady ustawiania różnych wartości parametru verticalArrangement dla elementów:FlowRow

Układ pionowy ustawiony na FlowRow

Wynik

Arrangement.Top (Default)

Układ górnej części kontenera

Arrangement.Bottom

Układ dolnej części kontenera

Arrangement.Center

Układ środkowy kontenera

W przypadku FlowColumn podobne opcje są dostępne w horizontalArrangement. Domyślne ułożenie wzdłuż osi poprzecznej to Arrangement.Start.

Wyrównanie poszczególnych elementów

Możesz chcieć umieścić poszczególne elementy w wierszu z różnym wyrównaniem. Różni się od verticalArrangementhorizontalArrangement, ponieważ wyrównuje elementy w bieżącym wierszu. Możesz to zrobić za pomocą Modifier.align().

Jeśli na przykład elementy w FlowRow mają różną wysokość, wiersz przyjmuje wysokość największego elementu i stosuje Modifier.align(alignmentOption) do elementów:

Wyrównanie w pionie ustawione na FlowRow

Wynik

Alignment.Top (Default)

Elementy wyrównane do góry

Alignment.Bottom

Elementy wyrównane do dołu

Alignment.CenterVertically

Elementy wyrównane do środka

W przypadku FlowColumn dostępne są podobne opcje. Domyślne wyrównanie to Alignment.Start.

Maksymalna liczba elementów w wierszu lub kolumnie

Parametry maxItemsInEachRow lub maxItemsInEachColumn określają maksymalną liczbę elementów na osi głównej, które mogą się zmieścić w jednym wierszu, zanim zostaną przeniesione do następnego. Domyślna wartość to Int.MAX_INT, która pozwala na umieszczenie jak największej liczby elementów, o ile ich rozmiary pozwalają na zmieszczenie się w wierszu.

Na przykład ustawienie maxItemsInEachRow wymusza, aby początkowy układ zawierał tylko 3 elementy:

Nie ustawiono wartości maksymalnej

maxItemsInEachRow = 3

Brak maksymalnej wartości w wierszu pliku danych Maksymalna liczba elementów ustawiona w wierszu przepływu

Wagi produktów

Waga powiększa element na podstawie jego współczynnika i dostępnego miejsca w wierszu, w którym został umieszczony. Ważne jest, aby znać różnicę między FlowRowRow w sposobie wykorzystania wag do obliczania szerokości elementu. W przypadku Rows waga jest obliczana na podstawie wszystkich elementów w Row. W przypadku FlowRow waga jest oparta na elementach w wierszu, w którym znajduje się element, a nie na wszystkich elementach w kontenerze FlowRow.

Jeśli na przykład masz 4 elementy, które znajdują się na jednej linii, a ich wagi to odpowiednio 1f, 2f, 1f3f, łączna waga wynosi 7f. Pozostała przestrzeń w wierszu lub kolumnie zostanie podzielona przez 7f. Następnie szerokość każdego elementu zostanie obliczona za pomocą wzoru: weight * (remainingSpace / totalWeight).

Możesz użyć kombinacji Modifier.weight i maksymalnej liczby elementów z FlowRow lub FlowColumn, aby utworzyć układ siatki. To podejście jest przydatne do tworzenia elastycznych układów, które dostosowują się do rozmiaru urządzenia.

Wagi można wykorzystać na kilka sposobów. Przykładem może być siatka, w której elementy mają równe rozmiary, jak pokazano poniżej:

Siatka utworzona z wierszem przepływu
Rysunek 2. Tworzenie siatki za pomocą FlowRow

Aby utworzyć siatkę z elementami o równych rozmiarach, możesz wykonać te czynności:

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

Ważne jest, że jeśli dodasz kolejny element i powtórzysz go 10 razy zamiast 9, ostatni element zajmie całą ostatnią kolumnę, ponieważ łączna waga całej kolumny wyniesie 1f:

Ostatni element w pełnym rozmiarze w siatce
Rysunek 3. Używanie FlowRow do tworzenia siatki, w której ostatni element zajmuje całą szerokość

Możesz łączyć wagi z innymi Modifiers, np. Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio) lub Modifier.fillMaxWidth(fraction). Wszystkie te modyfikatory działają razem, aby umożliwić elastyczne określanie rozmiaru elementów w FlowRow (lub FlowColumn).

Możesz też utworzyć naprzemienną siatkę z elementami o różnych rozmiarach, w której 2 elementy zajmują po połowie szerokości, a 1 element zajmuje całą szerokość następnej kolumny:

Naprzemienna siatka z wierszem przepływu
Rysunek 4. FlowRow z wierszami o naprzemiennych rozmiarach

Możesz to osiągnąć za pomocą tego kodu:

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

Rozmiary ułamkowe

Za pomocą Modifier.fillMaxWidth(fraction) możesz określić rozmiar kontenera, który powinien zajmować element. Różni się to od działania funkcji Modifier.fillMaxWidth(fraction) w przypadku elementów Row lub Column, ponieważ elementy Row/Column zajmują procent pozostałej szerokości, a nie całą szerokość kontenera.

Na przykład poniższy kod daje różne wyniki w zależności od tego, czy użyjesz znaku FlowRow, czy 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: Środkowy element o szerokości 0,7 ułamka szerokości całego kontenera.

Ułamkowa szerokość z wierszem przepływu

Row: środkowy element zajmuje 0,7% pozostałej szerokości Row.

Szerokość ułamkowa z wierszem

fillMaxColumnWidth()fillMaxRowHeight()

Zastosowanie właściwości Modifier.fillMaxColumnWidth() lub Modifier.fillMaxRowHeight() do elementu wewnątrz elementu FlowColumn lub FlowRow powoduje, że elementy w tej samej kolumnie lub wierszu zajmują taką samą szerokość lub wysokość jak największy element w kolumnie lub wierszu.

W tym przykładzie użyto tagu FlowColumn do wyświetlenia listy deserów na Androida. Możesz zobaczyć różnicę w szerokości poszczególnych elementów, gdy do elementów zastosowano atrybut Modifier.fillMaxColumnWidth(), a gdy nie zastosowano, i gdy elementy są zawijane.

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() zastosowana do każdego produktu

fillMaxColumnWidth

Brak ustawionych zmian szerokości (zawijanie elementów)

Nie ustawiono maksymalnej szerokości kolumny wypełnienia