Jetpack Compose中如何高效实现带动画的数千项可折叠网格分区
解决LazyVerticalGrid分区折叠动画的性能优化方案
针对你在单个LazyVerticalGrid中实现带动画的分区折叠功能时遇到的性能问题,这里提供几个高效的优化方案,既保留单网格的性能优势,又能实现流畅的折叠动画:
1. 缩小AnimatedVisibility的作用范围
不要给每个列表项单独添加AnimatedVisibility,而是将整个分区的条目块用AnimatedVisibility包裹,同时手动处理分区间距替代原有的verticalArrangement,减少动画节点数量:
LazyVerticalGrid( modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp), columns = GridCells.Fixed(5), ) { viewState.sections.forEach { section -> // 分区标题(跨列) item(span = { GridItemSpan(maxLineSpan) }) { InventorySectionHeader(section = section, intent = intent) } // 用AnimatedVisibility包裹整个分区的条目集合 AnimatedVisibility( visible = !section.collapsed, enter = expandVertically(expandFrom = Alignment.Top) + fadeIn(), exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut(), modifier = Modifier.animateContentSize() ) { items(items = section.items, key = { it.id }) { item -> InventorySectionItem(item = item, intent = intent) } } // 手动添加分区间的间距,避免原verticalArrangement导致的空空间问题 if (viewState.sections.last() != section) { item(span = { GridItemSpan(maxLineSpan) }) { Spacer(modifier = Modifier.height(20.dp)) } } } }
这种方式将动画范围从单个item提升到整个分区条目集合,大幅减少Compose动画节点的数量,直接缓解性能衰减问题。
2. 优化重组逻辑,减少不必要的计算
通过remember缓存展开状态,并同步外部viewState的变化,避免频繁的重组:
LazyVerticalGrid( modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp), columns = GridCells.Fixed(5), ) { viewState.sections.forEach { section -> // 用remember缓存展开状态,减少不必要的重组 val isExpanded = remember { mutableStateOf(!section.collapsed) } // 同步viewState的外部状态变化 LaunchedEffect(section.collapsed) { isExpanded.value = !section.collapsed } // 标题点击切换展开状态 item(span = { GridItemSpan(maxLineSpan) }) { InventorySectionHeader( section = section, intent = intent, onToggle = { isExpanded.value = !isExpanded.value } ) } AnimatedVisibility( visible = isExpanded.value, enter = expandVertically(expandFrom = Alignment.Top) + fadeIn(), exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut(), modifier = Modifier.animateContentSize() ) { items(items = section.items, key = { it.id }) { item -> InventorySectionItem(item = item, intent = intent) } } // 分区间距处理 if (viewState.sections.last() != section) { item(span = { GridItemSpan(maxLineSpan) }) { Spacer(modifier = Modifier.height(20.dp)) } } } }
3. 额外性能优化技巧
- 确保
InventorySectionItem的参数都是稳定类型(如data class),避免无意义的重组; - 提前在viewState中完成所有数据过滤、排序等计算,不要在Composable函数或LazyGrid的items块中做复杂逻辑;
- 调整动画的
animationSpec,适当缩短动画时长(比如用spring(stiffness = Spring.StiffnessMedium)),减少动画期间的性能消耗。
这些方案既保留了单个LazyVerticalGrid的高性能加载优势,又能实现流畅的分区折叠动画,无需切换到多网格的低性能方案。
内容的提问来源于stack exchange,提问作者Drackmord
相关产品推荐
相关产品推荐

