1. 为什么选择LazyVerticalGrid?
在Android应用开发中,展示网格布局的需求非常普遍。传统的RecyclerView虽然能通过GridLayoutManager实现网格效果,但在Jetpack Compose时代,LazyVerticalGrid提供了更简洁、更强大的解决方案。
我最近在一个电商类App项目中就遇到了商品展示的需求。最初尝试用传统的RecyclerView实现,但发现代码量较大,而且处理不同屏幕尺寸的适配比较麻烦。切换到LazyVerticalGrid后,不仅代码精简了约40%,而且自适应效果出奇地好。
LazyVerticalGrid的核心优势在于:
- 声明式UI:完全遵循Compose的设计理念,用更少的代码表达UI逻辑
- 自动适配:内置对不同屏幕尺寸和方向变化的处理
- 性能优化:延迟加载机制确保大数据集下的流畅滚动
- 灵活布局:支持动态调整列数和间距
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础使用:创建一个简单的网格
2.1 基本结构
让我们从最简单的例子开始。要使用LazyVerticalGrid,首先需要添加依赖:
kotlin复制implementation "androidx.compose.foundation:foundation:1.3.1"
然后可以这样构建一个基础网格:
kotlin复制val items = (1..100).map { "Item $it" }
LazyVerticalGrid(
columns = GridCells.Fixed(3), // 固定3列
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(8.dp)
) {
items(items) { item ->
Card(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth(),
elevation = 4.dp
) {
Text(
text = item,
modifier = Modifier.padding(16.dp)
)
}
}
}
这个例子创建了一个3列的网格,包含100个简单的卡片项。关键参数说明:
columns:定义列数和列宽策略contentPadding:为整个网格内容添加内边距items:数据列表和项内容构建器
2.2 列数配置策略
LazyVerticalGrid提供了三种列数配置方式:
- 固定列数(GridCells.Fixed)
kotlin复制columns = GridCells.Fixed(3) // 始终显示3列
- 自适应宽度(GridCells.Adaptive)
kotlin复制columns = GridCells.Adaptive(120.dp) // 每列至少120dp,根据可用空间自动调整列数
- 固定宽度(GridCells.FixedSize)
kotlin复制columns = GridCells.FixedSize(150.dp) // 每列固定150dp宽度
在实际项目中,我推荐使用GridCells.Adaptive,因为它能自动适应不同屏幕尺寸。例如在平板上可能显示5列,而在手机上只显示2列,无需额外代码处理。
3. 高级功能与优化技巧
3.1 添加头部和尾部
与RecyclerView类似,我们可以在网格中添加特殊项:
kotlin复制LazyVerticalGrid(columns = GridCells.Fixed(2)) {
item(span = { GridItemSpan(2) }) {
// 跨两列的头部
HeaderComponent()
}
items(items) { item ->
GridItem(item)
}
item(span = { GridItemSpan(2) }) {
// 跨两列的尾部
FooterComponent()
}
}
span参数允许项跨越多列。这在电商应用中特别有用,比如在商品列表顶部放置一个轮播广告。
3.2 性能优化实践
虽然LazyVerticalGrid本身已经做了很多性能优化,但在实际使用中还是需要注意:
- 避免复杂计算:不要在项组合函数中进行耗时操作
- 合理使用key:为items提供稳定的key,帮助Compose正确识别项
kotlin复制items(items, key = { it.id }) { item ->
// ...
}
- 图片加载优化:使用Coil或Glide等库,并设置合适的大小
kotlin复制AsyncImage(
model = item.imageUrl,
contentDescription = null,
modifier = Modifier.size(120.dp),
contentScale = ContentScale.Crop
)
我在项目中曾遇到滚动卡顿的问题,最终发现是因为在项组合中直接解析日期字符串。将解析移到ViewModel中处理后,性能立即提升了60%。
3.3 交互增强
为网格项添加点击交互:
kotlin复制items(items) { item ->
Card(
modifier = Modifier
.padding(4.dp)
.fillMaxWidth()
.clickable {
// 处理点击事件
onItemClick(item)
},
elevation = 4.dp
) {
// 项内容
}
}
对于长按操作,可以使用combinedClickable:
kotlin复制.combinedClickable(
onClick = { /* 点击处理 */ },
onLongClick = { /* 长按处理 */ }
)
4. 常见问题与解决方案
4.1 网格项高度不一致问题
默认情况下,网格项的高度由内容决定,这可能导致行高不一致。解决方案是固定高度:
kotlin复制items(items) { item ->
Box(
modifier = Modifier
.padding(4.dp)
.height(200.dp) // 固定高度
) {
// 项内容
}
}
或者使用aspectRatio保持宽高比:
kotlin复制.aspectRatio(1f) // 1:1的正方形
4.2 滚动位置记忆
当离开页面再返回时,默认会重置滚动位置。要记住滚动位置,可以使用rememberLazyListState:
kotlin复制val listState = rememberLazyListState()
LazyVerticalGrid(
state = listState,
// ...
)
// 在ViewModel中保存和恢复状态
val scrollState = listState.firstVisibleItemScrollOffset
4.3 与Paging库集成
对于分页加载数据,可以与Paging 3无缝集成:
kotlin复制val pagingItems = viewModel.pagingData.collectAsLazyPagingItems()
LazyVerticalGrid(columns = GridCells.Fixed(2)) {
items(pagingItems.itemCount) { index ->
val item = pagingItems[index]
item?.let {
GridItem(it)
} ?: PlaceholderItem()
}
if (pagingItems.loadState.append is LoadState.Loading) {
item(span = { GridItemSpan(2) }) {
LoadingIndicator()
}
}
}
5. 实际项目中的最佳实践
经过多个项目的实践,我总结了以下经验:
- 响应式设计:使用
Adaptive列策略配合WindowSizeClass,为不同设备尺寸提供最佳体验
kotlin复制val windowSizeClass = calculateWindowSizeClass(activity)
val columns = when (windowSizeClass.widthSizeClass) {
WindowWidthSizeClass.Compact -> GridCells.Fixed(2)
WindowWidthSizeClass.Medium -> GridCells.Fixed(3)
WindowWidthSizeClass.Expanded -> GridCells.Fixed(5)
else -> GridCells.Adaptive(150.dp)
}
-
项内容优化:避免在项组合中使用过多嵌套,扁平化布局结构提升性能
-
主题一致性:通过
MaterialTheme确保网格项与整体应用风格一致
kotlin复制Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant
)
) {
// 内容
}
- 测试策略:为网格编写UI测试时,使用
onNodeWithTag定位特定项
kotlin复制composeTestRule.onNodeWithTag("grid_item_0").assertIsDisplayed()
在最近的一个项目中,我们通过合理使用LazyVerticalGrid,将商品列表页的代码量减少了35%,同时滚动性能提升了40%。特别是在处理不同屏幕尺寸时,不再需要编写大量的条件判断代码,大大提高了开发效率。
