使用 LazyListScope 嵌套可组合项

Using LazyListScope Nested Composables

我有一个可组合项需要迭代并呈现 Map<String, List<String>>。他们的关键是“header”和列表sub-items.

我想这样写我的代码:

@Composable
fun renderFullMap(groupedItems: Map<String, List<String>>) {
  LazyColumn {
    groupedItems.forEach { (header, things) ->
      renderSection(header, things)
    }
  }
}

@Composable
fun renderSection(header: String, things: List<String>) {
  stickyHeader { Text(header) }
  items(things) { thing -> Text(thing) }
}

(实际上,实际数据和renderSection都比较复杂,但归结为这个基本思想。)

这行不通。它告诉我:

@Composable invocations can only happen from the context of a @Composable function

如果我使用 items 遍历我的地图键,我会得到一个不同的错误:

@Composable
fun renderFullMap(groupedItems: Map<String, List<String>>) {
  LazyColumn {
    items(groupedItems.keys.toList()) { header ->
      renderSection(header, groupedItems[header])
    }
  }
}

在此版本中,stickyHeaderitemsrenderSection 中未定义。

我尝试的最后一件事 - 在 renderSection 前加上 LazyListScope.:

@Composable
fun LazyListScope.renderSection(header: String, things: List<String>) {
  stickyHeader { Text(header) }
  items(things) { thing -> Text(thing) }
}

这只是暗中刺杀。如果我在 forEach 中调用它,它会告诉我它给了我第一个关于只能从其他可组合项调用的可组合项的错误。如果我从 items():

中调用它

'fun LazyListScope.renderSection(header: String, things: List): Unit' can't be called in this context by implicit receiver. Use the explicit one if necessary

我不会假装知道那是什么意思。

我该如何进行这项工作?我怀疑我需要以某种方式将 LazyListScope 向下扩展到 renderSection 但不清楚如何。

编辑:我有点让它起作用了,但是当我四处滚动时,我的列表项正在成倍增加。此代码编译:

@Composable
fun renderFullMap(groupedItems: Map<String, List<String>>) {
  LazyColumn {
    val scope = this
    items(groupedItems.keys.toList()) { header ->
      scope.renderSection(header, groupedItems[header])
    }
  }
}

@Composable
fun LazyListScope.renderSection(header: String, things: List<String>) {
  stickyHeader { Text(header) }
  items(things) { thing -> Text(thing) }
}

但是我不知道为什么列表的内容不正常。

您的第一种方法接近于正确的方法,您需要从 renderSection 中删除 @Composable 并添加 LazyListScope 上下文:

@Composable
fun renderFullMap(groupedItems: Map<String, List<String>>) {
  LazyColumn {
    groupedItems.forEach { (header, things) ->
      renderSection(header, things)
    }
  }
}

fun LazyListScope.renderSection(header: String, things: List<String>) {
  stickyHeader { Text(header) }
  items(things) { thing -> Text(thing) }
}