Ustawianie właściwości kontenera

Możesz zdefiniować konfigurację kontenera siatki, aby tworzyć elastyczne układy, które dostosowują się do różnych rozmiarów ekranu i typów treści. Na tej stronie dowiesz się, jak:

Określanie siatki

Siatka składa się z kolumn i wierszy. Kompozycja Grid ma parametr config, który akceptuje funkcję lambda do definiowania kolumn i wierszy w GridConfigurationScope. W tym przykładzie zdefiniowano siatkę z 3 wierszami i 2 kolumnami, z których każda ma stały rozmiar określony w Dp:

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
    }
) {
}

Umieszczanie elementów w siatce

Grid pobiera elementy interfejsu w funkcji lambda content i umieszcza je w komórkach siatki. Siatka rozmieszcza elementy niezależnie od tego, czy wiersze i kolumny zostały zdefiniowane. Domyślnie funkcja Grid próbuje umieścić element interfejsu w dostępnej komórce siatki w wierszu. Jeśli nie może tego zrobić, umieszcza go w dostępnej komórce siatki w następnym wierszu. Jeśli nie ma pustych komórek, Grid utworzy nowy wiersz.

W poniższym przykładzie siatka ma 6 komórek i w każdej z nich umieszczona jest karta (rysunek 1). Każda komórka siatki ma wymiary 160dp x 90dp, co daje łączny rozmiar siatki 320dp x 270dp.

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
    }
) {
    Card1()
    Card2()
    Card3()
    Card4()
    Card5()
    Card6()
}

Sześć kart jest ułożonych w siatce z 3 wierszami i 2 kolumnami.
Rysunek 1. Sześć kart jest umieszczonych w siatce z 3 wierszami i 2 kolumnami.

Aby zmienić to domyślne działanie na wypełnianie według kolumny, ustaw wartość właściwości flow na GridFlow.Column.

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
        gap(8.dp)
        flow = GridFlow.Column // Grid tries to place items to fill the column
    },
) {
    Card1()
    Card2()
    Card3()
    Card4()
    Card5()
    Card6()
}

Funkcja przepływu zmienia kierunek umieszczania elementów.
Rysunek 2. GridFlow.Row (lewa) i GridFlow.Column (prawa).

Zarządzanie rozmiarem ścieżki

Wiersze i kolumny są łącznie nazywane ścieżką siatki. Rozmiar ścieżki siatki możesz określić na jeden z tych sposobów:

  • Stały (Dp): przydziela określony rozmiar (np. column(180.dp)).
  • Procent (Float): przydziela procent całkowitej dostępnej przestrzeni od 0.0f do 1.0f (np. row(0.5f) dla 50%).
  • Elastyczny (Fr): rozdziela pozostałą przestrzeń proporcjonalnie po obliczeniu ścieżek o stałej szerokości i ścieżek procentowych. Jeśli na przykład 2 wiersze mają wartości 1.fr3.fr, ten drugi zajmuje 75% pozostałej wysokości.
  • Wewnętrzny: rozmiar ścieżki jest dostosowywany do zawartości. Więcej informacji znajdziesz w artykule Określanie rozmiaru ścieżki siatki w sposób wewnętrzny.

W przykładzie poniżej do określenia wysokości wierszy użyto różnych opcji rozmiaru ścieżki:

Grid(
    config = {
        column(1f)

        row(100.dp)
        row(0.2f)
        row(1.fr)
        row(GridTrackSize.Auto)
    },
    modifier = Modifier.height(480.dp)
) {
    PastelRedCard("Fixed(100.dp)")
        PastelGreenCard("Percentage(0.2f)")
    PastelBlueCard("Flex(1.fr)")
        PastelYellowCard("Auto")

}

Wysokości wierszy określone za pomocą 4 podstawowych opcji określania rozmiaru ścieżki.
Rysunek 3. Wysokości wierszy zdefiniowane za pomocą 4 podstawowych opcji określania rozmiaru ścieżki w Grid.

Ustawianie minimalnego rozmiaru elastycznych ścieżek siatki

Gdy w kontenerze siatki nie ma już miejsca, standardowa elastyczna ścieżka może się zmniejszyć do 0.dp. Aby temu zapobiec i mieć pewność, że treść nie zostanie zniekształcona, użyj GridTrackSize.MinMax, aby wymusić minimalny rozmiar, zachowując elastyczność ścieżki.

W tym przykładzie do pierwszego wiersza przypisano co najmniej 100.dp:

Grid(
    config = {
        column(1f)
        // The first row has a minimum height of 100.dp and can expand to 
        // the half of the remaining space.
        row(GridTrackSize.MinMax(100.dp, 1.fr))
        // The second row takes the half of the remaining space.
        row(1.fr)
        // The third row has a fixed height of 200.dp.
        row(200.dp)
    },
    modifier = Modifier.size(360.dp) // Total grid height is 360.dp
) {
    PastelRedCard("MinMax(100.dp, 1.fr)")
        PastelGreenCard("Flex(1.fr)")
    PastelBlueCard("Fixed(200.dp)")
}

Wysokości wierszy określone za pomocą 4 podstawowych opcji określania rozmiaru ścieżki.
Rysunek 4. Pierwszy wiersz ma wysokość co najmniej 100.dp.

Ustawianie minimalnego rozmiaru ścieżki siatki do umieszczania list leniwych

Standardowe elastyczne ścieżki automatycznie wysyłają zapytania o rozmiary wewnętrzne elementów podrzędnych, aby ustalić rozmiar podstawowy. Jetpack Compose zabrania jednak wysyłania zapytań o rozmiary wewnętrzne SubcomposeLayout, które są podstawą komponentów, takich jak LazyColumnLazyRow.

Umieszczenie leniwej listy w standardowej elastycznej ścieżce powoduje awarię IllegalStateException. Aby bezpiecznie umieścić leniwe listy w elastycznej ścieżce siatki, użyj MinMax z wyraźnym minimalnym rozmiarem (np. 0.dp), aby pominąć wewnętrzny pomiar.

Grid(
    config = {
        column(1f)
        // The first row's height is determined by the height of the Text composable.
        row(GridTrackSize.Auto)
        // The second row occupies the remaining space, allowing the LazyColumn to scroll.
        row(GridTrackSize.MinMax(0.dp, 1.fr))

        gap(8.dp)
    },
    modifier = Modifier.size(width = 170.dp, height = 240.dp)
) {
    Text("LazyColumn in a Grid")
    // The LazyColumn is placed in the second row, filling the remaining space.
    LazyColumn(verticalArrangement = Arrangement.spacedBy(4.dp)) {
        items(100) { number ->
            PastelGreenCard("Card $number")
        }
    }
}

Wysokość wierszy określona za pomocą 4 podstawowych opcji rozmiaru ścieżki.
Rysunek 5. LazyColumn w komórce tabeli.

Określanie rozmiaru ścieżki siatki w sposób wewnętrzny

Rozmiar wewnętrzny możesz zastosować w przypadku elementu Grid, gdy chcesz, aby układ dostosowywał się do treści, a nie był wymuszany w stałym kontenerze. Rozmiar ścieżki siatki jest określany na podstawie tych wartości:

  • GridTrackSize.MaxContent: użyj maksymalnego rozmiaru wewnętrznego treści (np. szerokość jest określana przez pełną długość tekstu w bloku tekstowym bez zawijania).
  • GridTrackSize.MinContent: użyj minimalnego rozmiaru wewnętrznego treści (np. szerokość jest określana przez najdłuższe pojedyncze słowo w bloku tekstu).
  • GridTrackSize.Auto: użyj elastycznego rozmiaru ścieżki, który dostosowuje się do dostępnego miejsca. Domyślnie zachowuje się jak MaxContent, ale zmniejsza i zawija zawartość, aby zmieściła się w kontenerze nadrzędnym.

W poniższym przykładzie 2 teksty są umieszczone obok siebie. Rozmiar kolumny pierwszego tekstu jest określany przez minimalną szerokość wymaganą do wyświetlenia tekstu, a szerokość drugiej kolumny zależy od maksymalnej szerokości tekstu.

Grid(
    config = {
        column(GridTrackSize.MinContent)
        column(GridTrackSize.MaxContent)
        row(1.0f)
    },
    modifier = Modifier.width(480.dp)
) {
    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet.")
    Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras imperdiet.")
}

Rozmiary wewnętrzne określone w kolumnach.
Rysunek 5. Rozmiary wewnętrzne określone w kolumnach.

Ustawianie odstępów między wierszami i kolumnami

Po określeniu rozmiaru ścieżek siatki możesz zmodyfikować odstęp między siatkami, aby dopracować odstępy między ścieżkami. Odstęp między kolumnami możesz określić za pomocą funkcji columnGap, a odstęp między wierszami za pomocą funkcji rowGap. W przykładzie poniżej między wierszami występuje 16dp odstęp, a między kolumnami – 8dp odstęp (rysunek 5).

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
        rowGap(16.dp)
        columnGap(8.dp)
    }
) {
    Card1()
    Card2()
    Card3()
    Card4()
    Card5()
    Card6()
}

odstępy między wierszami i kolumnami;
Rysunek 6. odstępy między wierszami i kolumnami;

Możesz też użyć funkcji gap, aby określić odstępy o takim samym rozmiarze kolumny i wiersza oraz zdefiniować rozmiary kolumn i odstępów osobno za pomocą jednej funkcji. Ten kod dodaje do siatki 8dp odstępy:

Grid(
    config = {
        repeat(2) {
            column(160.dp)
        }
        repeat(3) {
            row(90.dp)
        }
        gap(8.dp) // Equivalent to columnGap(8.dp) and rowGap(8.dp)
    }
) {
    Card1()
    Card2()
    Card3()
    Card4()
    Card5()
    Card6()
}

Określanie obszarów siatki za pomocą nazwanych obszarów

Nazwane obszary umożliwiają przypisywanie nazw do grup komórek siatki, które są nazywane obszarami siatki. Podczas umieszczania elementów interfejsu w siatce możesz używać tych nazw zamiast indeksów współrzędnych.

Korzystanie z nazwanych obszarów ma 2 główne zalety, jeśli chodzi o czytelność kodu:

  • Podczas definiowania układu siatki cel i umiejscowienie oczekiwanych treści są jasne.
  • Podczas dodawania treści jej cel jest jasny.

Aby uporządkować złożone układy, możesz oddzielić fizyczną strukturę siatki od umieszczenia elementów podrzędnych, definiując semantyczne obszary siatki.

W funkcji config lambda użyj funkcji area w GridConfigurationScope, aby zarejestrować nazwane obszary w siatce. Następnie możesz przypisać do tych obszarów komponenty podrzędne za pomocą modyfikatora gridItem z odpowiednim identyfikatorem obszaru. Funkcja area mapuje identyfikator semantyczny (np. wartość klasy enum lub klucz tekstowy) na zbiór fizycznych współrzędnych siatki. Linie siatki i indeksy są liczone od 1 (czyli pierwszy wiersz to 1, a pierwsza kolumna to 1).

Możesz na przykład zdefiniować siatkę z 4 identyfikatorami obszarów:

/**
 * An enum representing the IDs for named areas within the grid.
 */
enum class GridAreaNames {
    Area1,
    Area2,
    Area3,
    Area4
}

Podaj nazwę obszaru za pomocą parametru areaId wraz ze współrzędnymi komórek i zakresami obszaru. Modyfikator gridItem używa areaId jako klucza do przypisania każdego elementu podrzędnego do wyznaczonego obszaru siatki, jak w tym przykładzie:

Grid(
    config = {
        // Define a single column that takes all available width.
        repeat(2) { column(0.5f) }

        // Define four rows, each taking 25% of the total height.
        repeat(4) { row(0.25f) }

        // Define named grid areas by associating an areaId with specific row and column indices.
        // Row and column indices are 1-based.
        area(areaId = GridAreaNames.Area1, row = 1, column = 1, columnSpan = 2)
        area(areaId = GridAreaNames.Area2, row = 2, column = 1, rowSpan = 3)
        area(areaId = GridAreaNames.Area3, rows = 2..3, columns = 2..2)
        area(areaId = GridAreaNames.Area4, row = 4, column = 2)

        gap(4.dp)
    },
    modifier = Modifier.size(360.dp)
) {
    PastelRedCard(
        "Area 1",
        // Use Modifier.gridItem(areaId) to place this composable into the
        // grid area defined with the matching ID in the config block.
        modifier = Modifier.gridItem(areaId = GridAreaNames.Area1)
    )
    PastelGreenCard(
        "Area 2",
        modifier = Modifier.gridItem(areaId = GridAreaNames.Area2)
    )
    PastelBlueCard(
        "Area 3",
        modifier = Modifier.gridItem(areaId = GridAreaNames.Area3)
    )
    PastelYellowCard(
        "Area 4",
        modifier = Modifier.gridItem(areaId = GridAreaNames.Area4)
    )
}

Korzystając z obszarów nazwanych, możesz reorganizować lub dostosowywać siatkę układu fizycznego (np. zmieniać wiersze, kolumny lub rozmiary ścieżek) w funkcji config lambda bez konieczności modyfikowania kolejności ani parametrów elementów kompozycyjnych podrzędnych.