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 responsywnych – 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 dotyczy elementu lub interfejsu filtrowania:

5 elementów w FlowRow, które w przypadku braku miejsca przechodzą do następnego wiersza.
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ływowe 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:

Układ poziomy ustawiony na FlowRow

Wynik

Arrangement.Start (Default)

Elementy uporządkowane z początkiem

Arrangement.SpaceBetween

Rozmieszczenie elementów z odstępami

Arrangement.Center

Elementy ułożone na środku

Arrangement.End

Elementy umieszczone na końcu

Arrangement.SpaceAround

Elementy rozmieszczone z zachowaniem odstępów

Arrangement.spacedBy(8.dp)

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

W przypadku FlowColumn dostępne są podobne opcje z wartością verticalArrangement, przy czym domyślnie jest to Arrangement.Top.

Układ osi poprzecznych

Oś poprzeczna to oś 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 w przypadku parametru 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

Wyśrodkowanie 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óżnymi wyrównaniami. 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ą znajdować się w jednym wierszu, zanim zostaną przeniesione do następnego. Domyślna wartość to Int.MAX_INT, która umożliwia wyświetlanie jak największej liczby elementów, o ile ich rozmiary pozwalają na zmieszczenie ich 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 liczby wierszy w 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ą tego 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 mogą Ci pomóc w różnych sytuacjach. Przykładem może być siatka, w której elementy mają równe rozmiary, jak pokazano poniżej:

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

Aby utworzyć siatkę z elementami o jednakowych 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)
    }
}

Jeśli dodasz kolejny element i powtórzysz go 10 razy zamiast 9, ostatni element zajmie całą ostatnią kolumnę, ponieważ łączna waga całego wiersza 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ść

Wagi można łączyć 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 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 Modifier.fillMaxColumnWidth() lub Modifier.fillMaxRowHeight() do elementu w 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 znacznika 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 tego atrybutu i 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