Grid 可组合项可创建结构化的二维屏幕布局。
Grid 使用明确定义的轨道(行和列)和间隙作为界面的基础架构,定义了自适应布局结构。
由于 Grid 是结构化容器,而不是延迟加载容器,因此您需要明确定义放置在其中的每个元素,而无需在滚动时回收项。因此,直接在 Grid 中呈现大型或动态数据集可能会导致性能瓶颈,因为所有项会同时进行组合。
如需在结构化屏幕布局中显示大型数据集合,请在 Grid 单元格中嵌入延迟加载组件,例如 LazyColumn 或 LazyRow。
但请注意:灵活轨道(具有 1.fr 等规范)会查询子元素的固有尺寸。由于 SubcomposeLayout 不支持固有测量传递,因此将延迟列表放置在灵活轨道内会导致 IllegalStateException 崩溃。如需将延迟列表安全地放置在灵活的网格轨道内,您必须使用 GridTrackSize.MinMax 尺寸(例如 minmax(0.dp, 1.fr))来绕过固有测量传递。
LazyColumn。最佳做法
- 使用延迟列表,而不是大型显式循环:如需在结构化
Grid中显示大型或动态数据集,请在特定网格单元中嵌入延迟组件(通常为LazyColumn或LazyRow),而不是针对项创建大型显式循环,因为Grid不会回收项,并且有 1,000 个轨道的限制。 - 为延迟列表使用
MinMax轨道大小调整:由于LazyColumn和LazyRow不支持固有测量传递(请参阅SubcomposeLayout),因此请在托管延迟组件的灵活轨道上使用GridTrackSize.MinMax,以安全地绕过固有测量。
所需要素
Grid:可组合布局,用于将内容放置在通过显式行和列轨道配置的二维网格结构中。LazyColumn:垂直滚动列表,仅组合和回收当前在屏幕上可见的项。GridTrackSize.MinMax:轨道大小调整属性,用于定义灵活的边界(min和max),以安全地托管延迟加载组件,而不会触发运行时测量崩溃。gridItem:ComposeModifier扩展程序,用于将子界面元素分配给Grid内的特定单元格或命名区域。
步骤
通过定义语义区域标识符、使用 minmax 大小调整配置网格轨道以实现延迟列表兼容性,以及在网格内容区域内嵌入 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 中,放置静态组件(Header 和 Footer),并使用 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 来定义整体二维页面结构,同时将 LazyColumn 嵌入到具有 minmax 大小的灵活轨道中,以高效回收列表项并避免运行时异常。