我有几千个项目需要在网格中显示。它们按类别划分,我希望这些类别可以折叠。
我认为实现此目的的最有效方法是使用单个
LazyVerticalGrid
,其中我将节标题作为带有 GridItemSpan(this.maxLineSpan)
的项目放置,同时在展开/折叠它们时在它们之间添加和删除项目。
我这样做了,效果很好,非常顺利。
LazyVerticalGrid(
modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp),
verticalArrangement = Arrangement.spacedBy(20.dp),
columns = GridCells.Fixed(5),
) {
viewState.sections.forEach { section ->
header { InventorySectionHeader(section = section, intent = intent) }
if (!section.collapsed) {
items(items = section.items, key = { it.id }) { item ->
InventorySectionItem(item = item, intent = intent)
}
}
}
}
但是,我还想为这些部分的打开/折叠设置动画,这一直是一个令人头痛的问题。 简单地用
items()
包裹 AnimatedVisibility
的内容是行不通的,因为即使折叠时 items()
仍然会被执行,并且单元格即使是空的,仍然会占用一些空间,使得标题彼此相距很远。
LazyVerticalGrid(
modifier = Modifier.fillMaxSize().padding(horizontal = 10.dp),
verticalArrangement = Arrangement.spacedBy(20.dp),
columns = GridCells.Fixed(5),
) {
viewState.sections.forEach { section ->
header { InventorySectionHeader(section = section, intent = intent) }
items(items = section.items, key = { it.id }) { item ->
AnimatedVisibility(
visible = !section.collapsed,
enter = expandVertically(expandFrom = Alignment.Top),
exit = shrinkVertically(shrinkTowards = Alignment.Top)) {
InventorySectionItem(item = item, intent = intent)
}
}
}
}
我发现我可以将
Modifier.animateItem()
添加到 items()
的内容中,但这似乎只支持 fadeIn/fadeOut
效果,而且我一生都无法使这些标题项以动画方式定位。
当然,我可以通过制作一个普通的列并对每个部分的内容使用多个惰性网格来获得所需的结果,但是当我尝试它时,性能明显下降,所以我宁愿没有动画。
还有什么我可以尝试的吗?
我认为你的解决方案已经走在正确的轨道上。这里唯一的事情似乎是你不能在你的方法中使用
verticalArrangement = Arrangement.spacedBy(20.dp)
,因为它还会在不可见的 AnimatedVisibility
内容之间添加空间。
相反,您需要在每个
Modifier.padding
上应用 item
以获得所需的间距。那么,当item
隐藏时,就不会造成任何间距。
不可能将所有项目的外观作为一个整体设置动画,但就像您现在已经在做的那样,您可以为每个单独的项目设置动画。
请看下面的代码:
@Composable
fun GridItemDemo() {
val gridSections = remember { mutableStateListOf(Section("Section 1"), Section("Section 2"), Section("Section 3")) }
LazyVerticalGrid(
columns = GridCells.Adaptive(150.dp),
modifier = Modifier.fillMaxSize()
) {
gridSections.forEachIndexed { anIndex, aSection ->
item(span = { GridItemSpan(this.maxLineSpan) }) {
Row(
modifier = Modifier.padding(horizontal = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(aSection.sectionTitle)
IconButton(
onClick = {
gridSections[anIndex] = gridSections[anIndex].copy(sectionExpanded = !aSection.sectionExpanded)
}
) {
Icon(
imageVector = if (aSection.sectionExpanded) Icons.Filled.ArrowDropUp else Icons.Filled.ArrowDropDown,
contentDescription = ""
)
}
}
}
items(aSection.childCount) { childIndex ->
AnimatedVisibility(
modifier = Modifier.clipToBounds(),
visible = aSection.sectionExpanded,
enter = slideInVertically(tween(150)) + fadeIn(tween(150)),
exit = slideOutVertically(tween(150)) + fadeOut(tween(150))
) {
ListItem(
modifier = Modifier.padding(bottom = 8.dp),
headlineContent = { Text("Three line list item") },
overlineContent = { Text("OVERLINE") },
supportingContent = { Text("Secondary text") },
leadingContent = {
Icon(
Icons.Filled.Favorite,
contentDescription = "Localized description",
)
},
trailingContent = { Text("meta") }
)
}
}
}
}
}
输出: