修复了 Jetpack Compose 中 LazyColumn 内的网格?

Fixed Grid inside LazyColumn in Jetpack Compose?

目前在 Jetpack Compose 中,此代码会抛出一个 IllegalStateException,因为您无法嵌套两个垂直滚动的可组合项:

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

我不希望网格本身滚动,而只是显示我传入其中的可组合项的固定网格。在 LazyColumn 中显示非滚动网格是否有任何解决方法?

如果你不介意使用不稳定的API,你可以使用LazyVerticalGrid并使用span参数让item取全宽,如@穆斯塔法 :

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

稳定之前,就是recommended

using stable components like LazyColumn and Row to achieve the same result.

可以通过实施 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)
        )
    }
}

如果您的数据列表较小且网格项目简单 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 */
    }
}

对我来说,我已经明确地添加了高度,它对我在 lazy colum 中的 LazyverticalGrid 工作得很好

 LazyVerticalGrid(
        cells = GridCells.Fixed(3),
        contentPadding = PaddingValues(5.dp),
        modifier = Modifier
            .layoutId("lazy_list")
            .height(200.dp)