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

Posted

技术标签:

【中文标题】修复了 Jetpack Compose 中 LazyColumn 内的网格?【英文标题】:Fixed Grid inside LazyColumn in Jetpack Compose? 【发布时间】: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 中显示非滚动网格是否有任何解决方法?

【问题讨论】:

【参考方案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 */
    

【讨论】:

以上是关于修复了 Jetpack Compose 中 LazyColumn 内的网格?的主要内容,如果未能解决你的问题,请参考以下文章

viewpager jetpack compose 中的垂直滚动不起作用

Jetpack compose 更新到 1.0.0-rc01 后无法预览

Jetpack All In Compose ?看各种Jetpack库在Compose中的使用

Jetpack-Compose 学习笔记—— Compose 布局你学会了么?

Android Jetpack Compose学习—— Jetpack compose基础布局

Android Jetpack Compose学习—— Jetpack compose基础布局