【问题标题】:Fixed Grid inside LazyColumn in Jetpack Compose?修复了 Jetpack Compose 中 LazyColumn 内的网格?
【发布时间】:2021-11-19 00:13:58
【问题描述】:

目前在 Jetpack Compose 中,此代码会引发 IllegalStateException,因为您不能嵌套两个垂直滚动的 Composable:

@ExperimentalFoundationApi
@Composable
fun MyLazyColumn() {
    LazyColumn {
        item {
            Text(text = "My LazyColumn Title")
        }
        item {
            LazyVerticalGrid(cells = GridCells.Fixed(4)) {
                items(10) {
                    Box(
                        modifier = Modifier
                            .size(50.dp)
                            .padding(5.dp)
                            .background(Color.Gray)
                    )
                }
            }
        }
    }
}

我不希望网格本身滚动,而只是显示我传递给它的 Composable 的固定网格。在LazyColumn 中显示非滚动网格是否有任何解决方法?

【问题讨论】:

    标签: android android-jetpack-compose composable lazycolumn


    【解决方案1】:

    如果您不介意使用不稳定的 API,您可以使用 LazyVerticalGrid 并使用 span 参数使 item 占据整个宽度,如 @Mustafa pointed out

    LazyVerticalGrid(
        cells = GridCells.Fixed(spanCount),
    ) {
        item(
            span = { GridItemSpan(spanCount) }
        ) {
            Text("Title")
        }
        items(10) {
            Text(it.toString())
        }
    }
    

    稳定之前是recommended

    使用LazyColumnRow 等稳定组件来实现相同的结果。

    可以通过实现gridItemsLazyColumn 一起使用来完成。

    fun LazyListScope.gridItems(
        count: Int,
        nColumns: Int,
        horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
        itemContent: @Composable BoxScope.(Int) -> Unit,
    ) {
        gridItems(
            data = List(count) { it },
            nColumns = nColumns,
            horizontalArrangement = horizontalArrangement,
            itemContent = itemContent,
        )
    }
    
    fun <T> LazyListScope.gridItems(
        data: List<T>,
        nColumns: Int,
        horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
        key: ((item: T) -> Any)? = null,
        itemContent: @Composable BoxScope.(T) -> Unit,
    ) {
        val rows = if (data.isEmpty()) 0 else 1 + (data.count() - 1) / nColumns
        items(rows) { rowIndex ->
            Row(horizontalArrangement = horizontalArrangement) {
                for (columnIndex in 0 until nColumns) {
                    val itemIndex = rowIndex * nColumns + columnIndex
                    if (itemIndex < data.count()) {
                        val item = data[itemIndex]
                        androidx.compose.runtime.key(key?.invoke(item)) {
                            Box(
                                modifier = Modifier.weight(1f, fill = true),
                                propagateMinConstraints = true
                            ) {
                                itemContent.invoke(this, item)
                            }
                        }
                    } else {
                        Spacer(Modifier.weight(1f, fill = true))
                    }
                }
            }
        }
    }
    

    用法:

    LazyColumn {
        item {
            Text(text = "My LazyColumn Title")
        }
        // with count
        gridItems(10, nColumns = 4) { index -> 
            Box(
                modifier = Modifier
                    .size(50.dp)
                    .padding(5.dp)
                    .background(Color.Gray)
            )
        }
        // or with list of items
        gridItems(listOf(1,2,3), nColumns = 4) { item ->
            Box(
                modifier = Modifier
                    .size(50.dp)
                    .padding(5.dp)
                    .background(Color.Gray)
            )
        }
    }
    

    【讨论】:

    • 我正在寻找一种在 LazyColumn 中实现 LazyVerticalGrid 的方法,这是完美的解决方案。
    • 这个解决方案在你有一个小的数据列表和简单的网格项目 UI 的情况下可以正常工作,但是当你的数据很大并且网格的项目有一个复杂的 UI 和状态时,它会变得滞后和重。
    • @MustafaIbrahim 您是否尝试过运行该应用程序的发布版本? LazyColumn 在调试中的性能要差得多。您是否也尝试过具有相同布局的普通单格LazyColumn?我不认为我的方法比普通的LazyColumn 增加了太多开销
    • @MustafaIbrahim LazyVerticalGrid1.2.* 以来的性能应该比我的解决方案更好,因为它是使用 LazyColumn 重写的,但在 1.1.* b> 我希望性能大致相同。
    【解决方案2】:

    如果您有少量数据列表和简单的网格项目 UI,这个公认的答案很好,并且工作正常,但是当您的数据很大并且网格的项目具有复杂的 UI 和状态时,它会变得迟钝和沉重.

    就我而言,我设法通过将 LazyVerticalGrid 作为网格项目和其他内容的容器来解决这个问题,现在它看起来像这样:

    val spanCount = 2
    LazyVerticalGrid(
        modifier = modifier
            .fillMaxWidth(),
        cells = GridCells.Fixed(spanCount),
        state = rememberLazyGridState(),
    ) {
        item(
            span = {
                /** Take a full row */
                GridItemSpan(currentLineSpan = spanCount)
            }
        ) {
            Column(
                modifier = Modifier.fillMaxWidth()
            ) {
                items.forEach {
                    /** Iterate over your items here */
                }
            }
        }
        items(
            items = gridItems
        ){gridItem->
            /** Grid items go here */
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-06-01
      • 2021-09-28
      • 1970-01-01
      • 2022-09-26
      • 2022-07-29
      • 2021-12-28
      • 2021-11-30
      • 1970-01-01
      相关资源
      最近更新 更多