Układy przepływu w sekcji Utwórz

FlowRowFlowColumn to komponenty podobne do RowColumn, ale różniące się tym, że elementy przepływają na następny wiersz, gdy w kontenerze zabraknie miejsca. W ten sposób utworzysz kilka wierszy lub kolumn. Liczba elementów w pozycji może być też kontrolowana przez ustawienie maxItemsInEachRow lub maxItemsInEachColumn. Do tworzenia układów elastycznych często możesz użyć elementów FlowRow i FlowColumn – treść nie zostanie obcięta, jeśli elementy są zbyt duże, by zmieścić się w jednym wymiarze. Połączenie maxItemsInEach* z elementem Modifier.weight(weight) może też ułatwić tworzenie układów, które w razie potrzeby wypełniają lub poszerzają szerokość wiersza lub kolumny.

Typowy przykład interfejsu użytkownika dla elementu lub filtrowania:

5 elementów w raporcie FlowRow, które pokazują przejście do następnej linii, gdy nie ma więcej miejsca.
Rysunek 1. Przykład FlowRow

Podstawowe użycie

Aby użyć funkcji FlowRow lub FlowColumn, utwórz te elementy kompozycyjne i umieść w nich elementy zgodnie ze standardowym procesem:

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

Po wprowadzeniu tego fragmentu interfejs wygląda jak powyżej, a elementy są automatycznie przenoszone do następnego wiersza, gdy w pierwszym wierszu nie ma więcej 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.

Ułożenie głównej osi: poziome lub pionowe

Główna oś to oś, na której są rozmieszczone elementy (np. w FlowRow elementy są rozmieszczone poziomo). Parametr horizontalArrangement w pliku FlowRow określa sposób rozmieszczania wolnego miejsca między elementami.

W tej tabeli znajdziesz przykłady ustawienia horizontalArrangement w elementach FlowRow:

Ustawiono rozmieszczenie poziome: FlowRow

Wynik

Arrangement.Start (Default)

Elementy uporządkowane według startu

Arrangement.SpaceBetween

Uporządkowanie elementów z odstępami

Arrangement.Center

Elementy ułożone w środku

Arrangement.End

Elementy uporządkowane na końcu

Arrangement.SpaceAround

Elementy rozmieszczone wokół siebie

Arrangement.spacedBy(8.dp)

Elementy odstępów o określonej wartości dp

W przypadku usługi FlowColumn podobne opcje są dostępne w usłudze verticalArrangement. Wartość domyślna to Arrangement.Top.

Ustawienie osi poprzecznej

Oś poprzeczna jest osią w przeciwnym kierunku niż oś główna. Na przykład w funkcji FlowRow jest to oś pionowa. Aby zmienić sposób rozmieszczania elementów na osi poprzecznej, użyj wartości verticalArrangement dla FlowRow i horizontalArrangement dla FlowColumn.

W tabeli poniżej znajdziesz przykłady ustawienia różnych wartości verticalArrangement w elemencie FlowRow:

Układ pionowy ustawiony na FlowRow

Wynik

Arrangement.Top (Default)

Układ kontenera u góry

Arrangement.Bottom

Układ kontenera na dole

Arrangement.Center

Rozmieszczanie Container Center

W przypadku FlowColumn dostępne są podobne opcje w horizontalArrangement. Domyślne ustawienie osi poprzecznej to Arrangement.Start.

Wyrównanie poszczególnych elementów

Możesz ustawić poszczególne elementy w wierszu z różnym wyrównaniem. Różni się od verticalArrangement i horizontalArrangement, ponieważ wyrównuje elementy w bieżącym wierszu. Możesz to zrobić za pomocą Modifier.align().

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

Wyrównanie w pionie ustawiono 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 i maxItemsInEachColumn określają maksymalną liczbę elementów na osi głównej, które można umieścić w jednym wierszu przed zawijaniem do następnego. Wartość domyślna to Int.MAX_INT, która zezwala na użycie jak największej liczby elementów, o ile tylko ich rozmiar mieści się w wierszu.

Na przykład ustawienie maxItemsInEachRow spowoduje, że początkowy układ będzie zawierać tylko 3 elementy:

Brak ustawionego maksimum

maxItemsInEachRow = 3

Nie ustawiono maksymalnej wartości w wierszu przepływu Maksymalna liczba elementów ustawiona w wierszu przepływu

Leniwe ładowanie elementów procesu

ContextualFlowRowContextualFlowColumn to wyspecjalizowane wersje elementów FlowRowFlowColumn, które umożliwiają opóźnione wczytywanie zawartości wiersza lub kolumny przepływu. Zawierają też informacje o pozycji elementów (indeksie, numerze wiersza i dostępnym rozmiarze), na przykład o tym, czy element znajduje się w pierwszym wierszu. Jest to przydatne w przypadku dużych zbiorów danych i jeśli potrzebujesz informacji kontekstowych na temat danego elementu.

Parametr maxLines ogranicza liczbę wyświetlanych wierszy, a parametr overflow określa, co ma się wyświetlać, gdy liczba elementów przekroczy limit. Dzięki temu możesz podać niestandardową wartość expandIndicator lub collapseIndicator.

Aby na przykład wyświetlić przycisk „+ (liczba pozostałych elementów)” lub „Pokaż mniej”:

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

Przykład wierszy przepływu kontekstowego
Rysunek 2. Przykład: ContextualFlowRow

Waga produktu

Waga zwiększa wagę elementu na podstawie jego współczynnika i dostępnej przestrzeni na linii, na której został umieszczony. Należy pamiętać, że FlowRowRow różnią się sposobem korzystania z wag do obliczania szerokości elementu. W przypadku Rows waga jest obliczana na podstawie wszystkich elementów w: Row. W przypadku FlowRow waga jest określana na podstawie elementów zamówienia w pozycji, w której znajduje się element, a nie wszystkich elementów w kontenerze FlowRow.

Jeśli na przykład masz 4 elementy, które mieszczą się w jednej linii, a każdy z nich ma inną wagę: 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ą: weight * (remainingSpace / totalWeight).

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

Poniżej znajdziesz kilka przykładów tego, czego możesz dokonać, używając wag. Przykładem jest siatka, w której elementy mają jednakowy rozmiar, jak pokazano poniżej:

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

Aby utworzyć siatkę o równych rozmiarach elementów, wykonaj 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 wynosi 1f:

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

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

Możesz też utworzyć naprzemienne siatkę z elementami o różnych rozmiarach, gdzie 2 elementy mają połowę szerokości, a jeden z nich zajmuje pełną szerokość następnej kolumny:

Naprzemienna siatka z wierszem przepływu
Rysunek 5. FlowRow z naprzemiennym rozmiarem wierszy

Można 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))
        }
    }
}

Ułamkowy rozmiar

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

Na przykład ten kod daje różne wyniki w zależności od tego, czy używasz funkcji 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: element środkowy o 0,7 części szerokości całego kontenera.

Szerokość ułamkowa z wierszem przepływu

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

Szerokość ułamkowa z wierszem

fillMaxColumnWidth()fillMaxRowHeight()

Zastosowanie Modifier.fillMaxColumnWidth() lub Modifier.fillMaxRowHeight() do elementu w FlowColumn lub FlowRow zapewnia, że elementy w tej samej kolumnie lub wierszu mają taką samą szerokość lub wysokość jak największy element w kolumnie/wierszu.

Na przykład w tym przykładzie użyto FlowColumn, aby wyświetlić listę deserów na Androida. Możesz zobaczyć różnicę w szerokości poszczególnych elementów, gdy zastosujesz do nich Modifier.fillMaxColumnWidth(), a także gdy jej nie zastosujesz i elementy się zawiną.

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

Do każdego elementu zastosowano Modifier.fillMaxColumnWidth()

FillMaxColumnColumn (Szerokość)

Brak ustawień zmiany szerokości (owijanie elementów)

Nie ustawiono szerokości kolumny Maks. wypełnienie