首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Jetpack组合:嵌套的LazyColumn / LazyRow

Jetpack组合:嵌套的LazyColumn / LazyRow
EN

Stack Overflow用户
提问于 2022-05-17 09:03:11
回答 3查看 6.9K关注 0票数 18

我读过类似的话题,但没有得到令人满意的结果:

我的用例是:来创建一个注释列表(数百个条目),并可能显示对每个注释的答复(每个条目有数百个条目)。

目前,不可能在另一个LazyColumn中执行嵌套LazyColumn,因为Compose将引发异常:

java.lang.IllegalStateException:垂直滚动组件的测量带有无限大的最大高度约束,这是不允许的。一个常见的原因是嵌套布局,如LazyColumn和Column(Modifier.verticalScroll())。如果要在项目列表之前添加标题,请在LazyColumn范围内的主项()之前添加一个标头作为单独的项()。这种情况还可能有其他原因:您的ComposeView被添加到具有一定权重的LinearLayout中,您应用了Modifier.wrapContentSize(un界= true)或编写了自定义布局。请尝试删除滚动容器上方层次结构中无限约束的来源。

以上链接(以及我所想到的其他链接)提供的解决方案是:

  • 使用固定高度的内部LazyColumn -我不能使用它,因为每个项目可以有不同的高度(例如:单行和多行注释)。
  • LazyColumn中使用普通的LazyColumn(而不是惰性的)--从性能上看,它不如懒惰的,当使用Android的Profiler和500个元素列表时,普通Column会在我的应用程序中使用350 my的内存,而使用惰性的Composables则使用220-240 my的内存。因此,它将无法正确回收。
  • 使用来自伴奏者的FlowColumn --我没有看到这个和普通的Column之间的任何性能差异,所以请看上面。
  • 夷平列表的数据源(将注释和回复显示为“主要”注释,并只进行UI更改以区分它们)--这是我目前正在使用的内容,但是当我向这个特性添加更多的复杂性时,它阻止了一些新的特性请求的实现。
  • 禁用内部LazyColumn的滚动使用新增加的组成1.2.0 userScrollEnabled参数-不幸的是,它引发了相同的错误,这是一种预期的行为(参见这里)。
  • 使用其他方法阻止滚动(也阻止它程序化) -相同的错误。
  • 使用其他LazyColumn.height()参数,如wrapContentHeight()或使用IntrinsicSize.Min -相同的错误。

还有其他解决办法吗?特别是考虑到这可以在不限制高度的情况下将懒惰的组件嵌套在苹果的SwiftUI中。

EN

回答 3

Stack Overflow用户

发布于 2022-09-30 10:53:55

我有一个类似的用例,而且我有一个LazyColumn的解决方案,这个解决方案对我来说很好,而且性能也很好,我的想法是将数据作为一个具有不同类型元素的大型LazyColumn来处理。因为评论回复现在是单独的列表项,所以您必须首先将数据扁平化,这样它才是一个大列表或多个列表。现在,对于子注释,您只需在前面添加一些填充内容,否则它们将显示为单独的惰性项。我还使用了LazyVerticalGrid而不是LazyColumn,因为我必须在最后显示一个画廊图片网格,您可能不需要这样做,但是如果需要,您必须在任何其他地方使用span选项,如下所示。

你会得到这样的东西:

代码语言:javascript
复制
LazyVerticalGrid(
        modifier = Modifier
            .padding(6.dp),
        columns = GridCells.Fixed(3)
    ) {
        item(span = { GridItemSpan(3) }) {
            ComposableTitle()
        }
        items(
            items = flattenedCommentList,
            key = { it.commentId },
            span = { GridItemSpan(3) }) { comment ->
                ShowCommentComposable(comment) 
                //here subcomments will have extra padding in front
        }
        item(span = { GridItemSpan(3) }) {
            ComposableGalleryTitle()
        }
        items(items = imageGalleryList,
            key = { it.imageId }) { image ->
                ShowImageInsideGrid(image) //images in 3 column grid
    }
}
票数 1
EN

Stack Overflow用户

发布于 2022-09-26 03:33:28

我用这个函数解决了这个问题

代码语言:javascript
复制
@Composable
fun NestedLazyList(
    modifier: Modifier = Modifier,
    outerState: LazyListState = rememberLazyListState(),
    innerState: LazyListState = rememberLazyListState(),
    outerContent: LazyListScope.() -> Unit,
    innerContent: LazyListScope.() -> Unit,
) {
    val scope = rememberCoroutineScope()
    val innerFirstVisibleItemIndex by remember {
        derivedStateOf {
            innerState.firstVisibleItemIndex
        }
    }
    SideEffect {
        if (outerState.layoutInfo.visibleItemsInfo.size == 2 && innerState.layoutInfo.totalItemsCount == 0)
            scope.launch { outerState.scrollToItem(outerState.layoutInfo.totalItemsCount) }
        println("outer ${outerState.layoutInfo.visibleItemsInfo.map { it.index }}")
        println("inner ${innerState.layoutInfo.visibleItemsInfo.map { it.index }}")
    }

    BoxWithConstraints(
        modifier = modifier
            .scrollable(
                state = rememberScrollableState {
                    scope.launch {
                        val toDown = it <= 0
                        if (toDown) {
                            if (outerState.run { firstVisibleItemIndex == layoutInfo.totalItemsCount - 1 }) {
                                Log.i(TAG, "NestedLazyList: down inner")
                                innerState.scrollBy(-it)
                            } else {
                                Log.i(TAG, "NestedLazyList: down outer")
                                outerState.scrollBy(-it)
                            }
                        } else {
                            if (innerFirstVisibleItemIndex == 0 && innerState.firstVisibleItemScrollOffset == 0) {
                                Log.i(TAG, "NestedLazyList: up outer")
                                outerState.scrollBy(-it)
                            } else {
                                Log.i(TAG, "NestedLazyList: up inner")
                                innerState.scrollBy(-it)
                            }
                        }
                    }
                    it
                },
                Orientation.Vertical,
            )
    ) {
        LazyColumn(
            userScrollEnabled = false,
            state = outerState,
            modifier = Modifier
                .heightIn(maxHeight)
        ) {
            outerContent()
            item {
                LazyColumn(
                    state = innerState,
                    userScrollEnabled = false,
                    modifier = Modifier
                        .height(maxHeight)

                ) {
                    innerContent()
                }
            }
        }

    }
}

我所做的就是:

首先,我使用lazyList将内部BoxWithConstraints的高度设置为父视图的高度,这允许内部列表填充屏幕,而不需要扩展懒散的概念。

然后,我通过禁用惰性滚动来控制滚动,并使父滚动可以确定滚动何时影响父列表以及子滚动何时应滚动。

在父级更改时,这仍然存在一些bud,在我的例子中,我使用了这个SideEffect

票数 0
EN

Stack Overflow用户

发布于 2022-10-13 19:06:46

根列可以使用rememberScrollState()。就像这样;

代码语言:javascript
复制
Column(
    modifier = Modifier
        .verticalScroll(rememberScrollState())) {
   
    LazyColumn {
        // your code
    }

    LazyRow {
        // your code
    }

}
票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72271130

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档