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 wierszu może być też kontrolowana przez ustawienie maxItemsInEachRow lub maxItemsInEachColumn. Do tworzenia układów responsywnych często używa się elementów FlowRowFlowColumn – treści nie będą obcinane, jeśli elementy są zbyt duże dla jednego wymiaru. Użycie kombinacji elementów maxItemsInEach*Modifier.weight(weight) może pomóc w tworzeniu układów, które w razie potrzeby wypełniają/rozwijają szerokość wiersza lub kolumny.

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

5 elementów w wierszu przepływu, pokazujących przelanie na następny wiersz, gdy nie ma już miejsca.
Rysunek 1. Przykład FlowRow

Podstawowe użycie

Aby używać komponentów FlowRow lub FlowColumn, utwórz te komponenty i umieścić 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. Gdy w pierwszym rzędzie zabraknie miejsca, elementy są automatycznie przenoszone do następnego rzędu.

Funkcje układu przepływowego

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 tabeli poniżej znajdziesz przykłady ustawień horizontalArrangement dla elementów FlowRow:

Ustawienie wyrównania poziomego: 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 z przestrzenią wokół nich

Arrangement.spacedBy(8.dp)

Elementy rozmieszczone w odstępach określonych w dp

W przypadku FlowColumn dostępne są podobne opcje z verticalArrangement, a domyślna wartość 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 różnych ustawień verticalArrangement dla elementów FlowRow:

Układ pionowy ustawiony na FlowRow

Wynik

Arrangement.Top (Default)

Układ kontenera

Arrangement.Bottom

Układ dołu kontenera

Arrangement.Center

Ustawienie środka kontenera

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. Ta funkcja różni się od funkcji verticalArrangement i horizontalArrangement, ponieważ wyrównuje elementy w ramach bieżącego wiersza. 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 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óra może się zmieścić w jednym wierszu przed przewinięciem do następnego. Wartość domyślna to Int.MAX_INT, która pozwala na wyświetlenie jak największej liczby elementów, o ile ich rozmiary umożliwiają ich umieszczenie na linii.

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

Brak ustawionego maksimum

maxItemsInEachRow = 3

Brak maksymalnej stawki w wierszu przepływu Maksymalna liczba elementów ustawiona w wierszu przepływu

Leniwe ładowanie elementów

ContextualFlowRowContextualFlowColumn to wyspecjalizowane wersje elementów FlowRowFlowColumn, które umożliwiają opóźnione wczytywanie zawartości wiersza lub kolumny przepływu. Zawierają one również informacje o pozycji produktów (indeks, numer wiersza i dostępna wielkość), np. czy produkt 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ć niestandardowy parametr 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 element 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 elementów Modifier.weight i maksymalna z elementami 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ć przemienną siatkę z różnymi rozmiarami elementów, w której 2 elementy zajmują po połowie szerokości, a jeden element zajmuje całą szerokość następnej kolumny:

Naprzemienna siatka z wierszem
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óżnica w sposobie działania elementu Modifier.fillMaxWidth(fraction) w przypadku elementów Row lub Column polega na tym, że elementy Row/Column zajmują procentową część pozostałej szerokości, a nie całej szerokości 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)
            )
        }
    }
}

Wartość Modifier.fillMaxColumnWidth() została zastosowana do każdego elementu

fillMaxColumnWidth

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

Nie ustawiono szerokości kolumny Maks. wypełnienie