Ленивые списки в сетке

Значок оценки в четыре звезды

Composable-функция Grid создает структурные двухмерные макеты экрана. Grid определяет структуру адаптивного макета с помощью явно заданных дорожек (строк и столбцов) и промежутков в качестве базовой архитектуры вашего пользовательского интерфейса.

Поскольку Grid – это структурный контейнер, а не контейнер с отложенной загрузкой, вам нужно явно определить каждый элемент, размещенный в нем, без повторного использования элементов при прокрутке. В результате рендеринг больших или динамических наборов данных непосредственно в Grid может вызвать проблемы с производительностью, поскольку все элементы компонуются одновременно.

Чтобы показывать большие наборы данных в структурированном макете экрана, встраивайте ленивые компоненты, такие как LazyColumn или LazyRow, в ячейки Grid. Но обратите внимание: гибкие дорожки (с такими спецификациями, как 1.fr) запрашивают внутренние размеры дочерних элементов. Поскольку SubcomposeLayout не поддерживает внутренние проходы измерения, размещение ленивого списка внутри гибкой дорожки приводит к сбою IllegalStateException. Чтобы безопасно разместить ленивые списки внутри гибкой сетки, необходимо использовать размер GridTrackSize.MinMax (например, minmax(0.dp, 1.fr)), чтобы обойти этап внутреннего измерения.

Макет экрана с верхним заголовком, прокручиваемым списком элементов в основной области контента и нижним колонтитулом.
Рисунок 1. Структурный макет экрана с верхним и нижним колонтитулами и встроенным элементом LazyColumn для контента.

Рекомендации

  • Используйте ленивые списки вместо больших явных циклов. Чтобы отображать большие или динамические наборы данных в структурированной сетке Grid, встраивайте ленивые компоненты (обычно LazyColumn или LazyRow) в определенные ячейки сетки, а не создавайте большие явные циклы по элементам, поскольку Grid не утилизирует элементы и имеет ограничение в 1000 дорожек.
  • Используйте размер дорожки MinMax для ленивых списков. Поскольку LazyColumn и LazyRow не поддерживают внутренние проходы измерения (см. SubcomposeLayout), используйте GridTrackSize.MinMax на гибких дорожках, на которых размещаются ленивые компоненты, чтобы безопасно обходить внутренние измерения.

Ингредиенты

  • Grid – компонуемый макет, который размещает элементы в двумерной сетке, настроенной с помощью явных строк и столбцов.
  • LazyColumn – вертикально прокручиваемый список, который составляет и повторно использует только элементы, видимые на экране.
  • GridTrackSize.MinMax – свойство размера дорожки, которое определяет гибкие границы (min и max) для безопасного размещения ленивых компонентов без сбоев измерения во время выполнения.
  • gridItem – расширение Compose Modifier, которое назначает дочерний элемент интерфейса определенной ячейке или именованной области внутри Grid.

Шаги

Структурируйте макет экрана, определив идентификаторы семантических областей, настроив дорожки сетки с размером minmax для совместимости с ленивым списком и встроив LazyColumn в область содержимого сетки.

1. Как настроить дорожки сетки и именованные области

Создайте класс enum, чтобы представить отдельные регионы макета экрана, и определите лямбду GridConfigurationScope для дорожек макета и именованных областей. Используйте GridTrackSize.MaxContent для строк верхнего и нижнего колонтитулов, чтобы они соответствовали размерам их содержимого, и используйте minmax(0.dp, 1.fr) для дорожки содержимого, на которой размещен ленивый список, чтобы выделить гибкое пространство без запроса неподдерживаемых внутренних измерений:

enum class ScreenArea {
    Header,
    Content,
    Footer
}


val lazyConfig: GridConfigurationScope.() -> Unit = {
    column(minmax(0.dp, 1.fr))
    row(GridTrackSize.MaxContent)
    row(minmax(0.dp, 1.fr))
    row(GridTrackSize.MaxContent)

    area(ScreenArea.Header, row = 1, column = 1)
    area(ScreenArea.Content, row = 2, column = 1)
    area(ScreenArea.Footer, row = 3, column = 1)
    gap(8.dp)
}

2. Разместите статические компоненты в сетке

В composable-функции передайте lazyConfig в контейнер Grid. Внутри лямбда-выражения content разместите статические компоненты (Header и Footer) и расположите их с помощью Modifier.gridItem() с соответствующими идентификаторами областей.

3. Встройте LazyColumn в область контента.

В ячейке контента встройте LazyColumn с помощью Modifier.gridItem(ScreenArea.Content). Поскольку в шаге 1 для дорожки контента было задано значение minmax(0.dp, 1.fr), LazyColumn может безопасно измерять и повторно использовать элементы при прокрутке, не запрашивая неподдерживаемые внутренние размеры:

@Composable
fun GridWithLazyColumn(
    modifier: Modifier = Modifier,
    items: List<String> = emptyList(),
) {
    Grid(
        modifier = modifier.fillMaxSize(),
        config = lazyConfig
    ) {
        Text("Header", Modifier.gridItem(ScreenArea.Header).padding(16.dp))
        Text("Footer", Modifier.gridItem(ScreenArea.Footer).padding(16.dp))

        // LazyColumn placed in the content area for large datasets
        LazyColumn(
            modifier = Modifier
                .gridItem(ScreenArea.Content)
                .fillMaxSize(),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            items(items) { item ->
                Text(item, Modifier.padding(16.dp))
            }
        }
    }
}

Результаты

Теперь макет экрана использует API Grid для определения общей двумерной структуры страницы, а LazyColumn встроен в гибкую дорожку с размером minmax для эффективной переработки элементов списка и предотвращения исключений во время выполнения.

Дополнительные ресурсы