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:

Definiowanie siatki

Siatka składa się z kolumn i wierszy. Funkcja kompozycyjna Grid ma parametr config, który akceptuje funkcję lambda do definiowania kolumn i wierszy w GridConfigurationScope. Poniższy przykład definiuje siatkę, która ma 3 wiersze i 2 kolumny, 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 Grid próbuje umieścić element interfejsu w dostępnej komórce siatki w wierszu. Jeśli nie jest to możliwe, umieszcza go w dostępnej komórce siatki w następnym wierszu. Jeśli nie ma pustych komórek, Grid tworzy nowy wiersz.

W przykładzie poniżej siatka ma 6 komórek, a w każdej z nich znajduje się 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 ułożonych w siatce z 3 wierszami i 2 kolumnami.

Aby zmienić to domyślne działanie na wypełnianie według kolumn, ustaw właściwość 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 (po lewej) i GridFlow.Column (po prawej).

Zarządzanie rozmiarem ścieżki

Wiersze i kolumny są wspólnie nazywane ścieżką siatki. Rozmiar ścieżki siatki możesz określić za pomocą jednej z tych metod:

  • Stały (Dp): przydziela określony rozmiar (np. column(180.dp)).
  • Procent (Float): przydziela procent łącznej dostępnej przestrzeni od 0.0f do 1.0f (np. row(0.5f) dla 50%).
  • Elastyczny (Fr): rozdziela pozostałe miejsce proporcjonalnie po obliczeniu ścieżek stałych i procentowych. Jeśli na przykład 2 wiersze mają ustawione wartości 1.fr i 3.fr, drugi z nich otrzyma 75% pozostałej wysokości.
  • Wewnętrzny: rozmiar ścieżki jest określany na podstawie jej zawartości. Więcej informacji znajdziesz w sekcji Określanie rozmiaru ścieżki siatki.

W przykładzie poniżej użyto różnych opcji rozmiaru ścieżki, aby zdefiniować wysokości wierszy:

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 zdefiniowane za pomocą 4 głównych opcji określania rozmiaru ścieżki.
Rysunek 3. Wysokości wierszy zdefiniowane za pomocą 4 głównych opcji 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 upewnić się, że treść nie zostanie ściśnięta, użyj GridTrackSize.MinMax, aby wymusić minimalny rozmiar, zachowując elastyczność ścieżki.

W tym przykładzie do pierwszego wiersza przydzielono 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 zdefiniowane za pomocą 4 głównych opcji określania rozmiaru ścieżki.
Rysunek 4. Pierwszy wiersz ma wysokość co najmniej 100.dp.

Ustawianie minimalnego rozmiaru ścieżki siatki na potrzeby umieszczania list z opóźnionym ładowaniem

Standardowe elastyczne ścieżki automatycznie wysyłają zapytania o rozmiary wewnętrzne elementów podrzędnych, aby określić rozmiar podstawowy. Jetpack Compose uniemożliwia jednak wysyłanie zapytań o rozmiary wewnętrzne elementu SubcomposeLayout, który obsługuje komponenty takie jak LazyColumn i LazyRow.

Umieszczenie listy typu lazy w standardowej ścieżce elastycznej powoduje awarię IllegalStateException. Aby bezpiecznie umieścić listy z opóźnionym ładowaniem w elastycznej ścieżce siatki, użyj MinMax z wyraźnym rozmiarem minimalnym (np. 0.dp), aby pominąć etap pomiaru wewnętrznego.

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ści wierszy zdefiniowane za pomocą 4 głównych opcji określania rozmiaru ścieżki.
Rysunek 5. LazyColumn w komórce tabeli.

Określanie rozmiaru ścieżki siatki na podstawie jej zawartości

Możesz użyć rozmiaru wewnętrznego dla elementu Grid, gdy chcesz, aby układ dostosowywał się do treści, zamiast wymuszać stały rozmiar kontenera. Rozmiar ścieżki siatki jest określany za pomocą 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 tekstu 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 tym przykładzie 2 teksty są umieszczone obok siebie. Rozmiar kolumny dla pierwszego tekstu jest określany przez wymaganą minimalną szerokość do wyświetlenia tekstu, a szerokość drugiej kolumny zależy od wymaganej 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ępy siatki, aby dostosować 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 tym przykładzie odstęp między wierszami wynosi 16dp, a między kolumnami – 8dp (rys. 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 ułatwiającej gap, aby zdefiniować odstępy o tym samym rozmiarze kolumny i wiersza oraz określić rozmiary kolumn i odstępów osobno za pomocą jednej funkcji. Ten kod dodaje do siatki odstępy o szerokości 8dp:

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

Definiowanie obszarów siatki za pomocą nazwanych obszarów

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

Używanie 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.
  • Cel dodawania treści jest jasny.

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

Wewnątrz funkcji lambda config użyj funkcji area w GridConfigurationScope, aby zarejestrować nazwane obszary w siatce. Następnie możesz przypisać elementy kompozycyjne podrzędne do tych obszarów, używając modyfikatora gridItem z odpowiednim identyfikatorem obszaru. Funkcja area mapuje identyfikator semantyczny (np. wartość klasy enum lub klucz ciągu znaków) na zestaw 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 oraz współrzędne i zakresy komórek 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)
    )
}

Dzięki nazwanym obszarom możesz reorganizować lub dostosowywać fizyczny układ siatki (np. zmieniać wiersze, kolumny lub rozmiary ścieżek) w funkcji lambda config bez konieczności modyfikowania kolejności lub parametrów podrzędnych funkcji kompozycyjnych.