android Jetpack组成:嵌套的惰性列/惰性行

jobtbby3  于 2023-03-06  发布在  Android
关注(0)|答案(3)|浏览(299)

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

目前还不能在另一个LazyColumn中嵌套LazyColumn,因为Compose会抛出异常:
java.lang.IllegalStateException:测量垂直可滚动组件时使用了无限大的最大高度约束,这是不允许的。常见原因之一是嵌套布局,如LazyColumn和Column(Modifier. verticalScroll())。如果要在项列表之前添加标题,请在LazyColumn范围内的主项()之前添加标题作为单独的项()。发生这种情况可能还有其他原因:您的合成视图已添加到具有一定权重的LinearLayout中,您应用了Modifier. wrapContentSize(unbounded = true)或编写了自定义布局。请尝试删除滚动容器上方层次结构中无限约束的来源。
上面的链接提供的解决方案(以及我想到的其他解决方案)是:

  • 对内部LazyColumn使用固定高度-我不能使用它,因为每个项目可以有不同的高度(例如:单行注解与多行注解)。
  • LazyColumn中使用普通Column(非惰性)-性能方面不如惰性的,当使用Android Studio的Profiler和500个元素的列表时,普通Column将在我的应用中使用350MB的RAM,而使用惰性Composables时将使用220 - 240MB。
  • 使用FlowColumn从伴奏-我没有看到任何性能差异,这一个和正常的Column,所以见上文。
  • 扁平化列表的数据源(将评论和回复都显示为"主"评论,并且只对UI进行更改以区分它们)-这是我目前使用的方法,但当我向此功能添加更多复杂性时,它阻止了一些新功能请求的实现。
  • 使用newly added in Compose 1.2.0userScrollEnabled参数禁用内部LazyColumn的滚动-不幸的是,它抛出了相同的错误,这是一个预期的行为(见here)。
  • 使用其他方法阻止滚动(也阻止它programatically)-同样的错误。
  • 使用其他LazyColumn.height()参数(如wrapContentHeight())或使用IntrinsicSize.Min-相同错误。

有没有其他解决这个问题的办法?特别是考虑到在苹果的SwiftUI中嵌套惰性组件而不限制高度是可行的。

igsr9ssn

igsr9ssn1#

我有一个类似的使用案例,我有一个带有单个LazyColumn的解决方案,它对我来说工作得很好,性能也很高,这个想法是把你的数据看作一个大的LazyColumn,它包含不同类型的元素。因为评论回复现在是独立的列表项,所以你必须首先把你的数据扁平化,这样它就变成了一个大列表或多个列表。注解,你只需要在前面添加一些填充,否则它们会显示为单独的lazy项。我还使用了LazyVerticalGrid而不是LazyColumn,因为我必须在最后显示图库图片的网格,你可能不需要,但如果你需要,你必须在其他地方使用span选项,如下所示。
你会得到这样的结果:

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
    }
}
kmpatx3s

kmpatx3s2#

我在这个函数中解决了这个问题

@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()
                }
            }
        }

    }
}

我所做的就是:
首先,我使用BoxWithConstraints将内部lazyList的高度设置为父视图的高度,这样可以让内部列表填充屏幕,而不会破坏惰性概念。
然后,我通过禁用惰性滚动来控制滚动,并使父列表可滚动,以确定滚动何时影响父列表以及子列表何时应该滚动。
芽这仍然有一些错误时,父大小改变,在我的情况下,我逃脱了这个SideEffect

cuxqih21

cuxqih213#

你可以使用rememberScrollState()作为根列。

Column(
    modifier = Modifier
        .verticalScroll(rememberScrollState())) {
   
    LazyColumn {
        // your code
    }

    LazyRow {
        // your code
    }

}

编辑;
以上工作不正确,这是正确的

LazyColumn {
  
  item {
    LazyRow {
      // your code
    }
  }

  items(yourList) {
    // your code  
  }

}

相关问题