网格中的延迟列表

四星评级图标

Grid 可组合函数用于创建结构化的二维屏幕布局。Grid 使用明确定义的轨道(行和列)和间距来定义自适应布局结构,作为界面基础架构。

由于 Grid 是结构性容器,而不是延迟加载容器,因此您需要明确定义放置在其中的每个元素,而无需在滚动时回收项目。因此,直接在 Grid 中渲染大型或动态数据集可能会导致性能瓶颈,因为所有项都会同时进行组合。

如需在结构化屏幕布局中显示大量数据集合,请在 Grid 单元格中嵌入 LazyColumnLazyRow 等延迟组件。但请注意:灵活轨道(具有 1.fr 等规范)会查询子元素的固有大小。由于 SubcomposeLayout 不支持内在测量传递,因此将延迟列表放置在灵活轨道内会导致 IllegalStateException 崩溃。为了安全地将延迟列表放置在灵活的网格轨道内,您必须使用 GridTrackSize.MinMax 大小调整(例如 minmax(0.dp, 1.fr))来绕过固有测量传递。

屏幕布局,顶部为标题,主要内容区域为可滚动的项目列表,底部为页脚。
图 1. 具有页眉、页脚和嵌入式 LazyColumn(用于显示内容)的结构化屏幕布局。

最佳做法

  • 使用延迟列表,而不是大型显式循环:为了在结构化 Grid 中显示大型或动态数据集,请在特定网格单元格内嵌入延迟组件(通常为 LazyColumnLazyRow),而不是针对项创建大型显式循环,因为 Grid 不会回收项,并且最多只能显示 1,000 个轨道。
  • 为延迟列表使用 MinMax 轨道尺寸调整:由于 LazyColumnLazyRow 不支持内在测量传递(请参阅 SubcomposeLayout),因此请在托管延迟组件的灵活轨道上使用 GridTrackSize.MinMax,以安全地绕过内在测量。

所需要素

  • Grid:一种可组合的布局,用于将项放置在通过显式行和列轨道配置的二维网格结构中。
  • LazyColumn:垂直滚动列表,仅组合和回收当前在屏幕上可见的项。
  • GridTrackSize.MinMax:用于跟踪尺寸调整的属性,用于定义灵活的边界(minmax),以便安全地托管延迟加载的组件,而不会触发运行时测量崩溃。
  • gridItem:用于将子界面元素分配给 Grid 内的特定单元格或命名区域的 Modifier 扩展函数。

步骤

通过以下方式构建屏幕布局:定义语义区域标识符,配置具有 minmax 大小的网格轨道以实现 LazyList 兼容性,以及将 LazyColumn 嵌入网格内容区域中。

1. 配置网格轨道和命名区域

创建 enum 类来表示屏幕布局的不同区域,并为布局轨道和命名区域定义 GridConfigurationScope lambda。使用 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. 将静态组件放置在网格中

在可组合项中,将 lazyConfig 传递给 Grid 容器。在 content lambda 内,放置静态组件(标题页脚),并使用 Modifier.gridItem() 及其各自的区域标识符来定位它们。

3. 在内容区域中嵌入 LazyColumn

在内容单元格中,使用 Modifier.gridItem(ScreenArea.Content) 嵌入 LazyColumn。 由于内容轨道在第 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))
            }
        }
    }
}

结果

您的屏幕布局现在利用 Grid API 来定义整体二维页面结构,同时在具有 minmax 大小的灵活轨道中嵌入 LazyColumn,以高效回收列表项并避免运行时异常。

其他资源