Jetpack compose 中的 [NestedScrollView + RecyclerView] 或 [Nested RecyclerView (Recycler inside another

Posted

技术标签:

【中文标题】Jetpack compose 中的 [NestedScrollView + RecyclerView] 或 [Nested RecyclerView (Recycler inside another recycler) 相当于啥【英文标题】:What is the equivalent of [NestedScrollView + RecyclerView] or [Nested RecyclerView (Recycler inside another recycler) in Jetpack composeJetpack compose 中的 [NestedScrollView + RecyclerView] 或 [Nested RecyclerView (Recycler inside another recycler) 相当于什么 【发布时间】:2021-06-28 16:49:27 【问题描述】:

我想在 Jetpack compose 中创建以下布局。

我尝试在垂直可滚动框中创建两个列表,但这是不可能的,因为我得到了这个错误: “java.lang.IllegalStateException:不允许在同一方向上嵌套可滚动布局,如 ScrollableContainer 和 LazyColumn。如果您想在项目列表之前添加标题,请查看 LazyColumn 组件,该组件具有 DSL api,它允许首先通过 item() 函数添加标题,然后通过 items() 添加项目列表。"

我尝试使用以下代码在父列表中创建两个不同的列表,但这也不起作用。

@Composable
fun MainList() 
    LazyColumn() 
        
        item 
            /* LazyRow code here */
        
        
        item 
            /* LazyColumn code here */
        
    

现在我不知道我还能尝试在同一个活动上实现两个列表(一个垂直和一个水平)并保持活动垂直滚动。

【问题讨论】:

【参考方案1】:

我认为最好的选择是 LazyVerticalGrid 允许对每个项目进行某种扩展逻辑,但看起来它尚不受支持(beta-03)。

所以我将把我的解决方案留在这里,对整个列表使用一个LazyColumn,对“我的书”部分使用LazyRow

LazyColumn(
    modifier = Modifier.fillMaxSize(),
) 
    // My Books section
    item 
        Column(modifier = Modifier.fillMaxWidth()) 
            Text("My Books")
            LazyRow 
                items(books)  item ->
                    // Each Item
                
            
        

    
    // Whishlisted Books title
    item 
        Text("Whishlisted Books", style = MaterialTheme.typography.h4)
    
    // Turning the list in a list of lists of two elements each
    items(wishlisted.windowed(2, 2, true))  item ->
        Row 
            // Draw item[0]
            // Draw item[1]
        
    


这是我的gist with the full solution,结果如下所示。

【讨论】:

非常感谢您花时间写详细的回复。它就像一个魅力:) Flow 似乎比通过 XML 制作视图要容易得多,这太疯狂了......【参考方案2】:

你可以这样做:

   Column(Modifier.fillMaxWidth()) 

        LazyRow() 
            items(itemsList)
                  //.....
                
        

       LazyColumn() 
           items(itemsList2)
               //..
           
       
    

或:

   Column(Modifier.fillMaxWidth()) 

        LazyRow() 
            items(itemsList)
               //....
            
        
       
       LazyVerticalGrid(cells = GridCells.Fixed(2)) 
           items(itemsList2.size)
               //....
           
       

    

【讨论】:

非常感谢您抽出宝贵时间提供详细的解决方案。虽然解决方案是准确的,但它不会滚动整个活动。因此,我将合并您(网格部分)和@nglauber 提供的解决方案。再次感谢。 快速提问:既然这里的 LazyVerticalGrid 被包裹在一个简单的 Column 中,你是否还能获得 LazyVerticalGrid 的回收优势?或者 Column 会在第一次渲染时尝试填充所有内容,包括 LazyVerticalGrid?【参考方案3】:

嵌套 RecyclerViews 的替代等效项是嵌套 LazyColumns,其中内部 LazyColumns 的 高度 是指定的或恒定的,而内部 LazyColumns 放置在 item 内 个块。

与公认的答案不同,这种方法依赖于 .height() 修饰符来避免“java.lang.IllegalStateException:在同一方向嵌套可滚动布局,如 ScrollableContainer 和 LazyColumn 是不允许的......”错误。此外,这种方法还解决了同方向嵌套滚动的情况。

这是一个示例代码和输出。

    @Composable
    fun NestedLists() 
        LazyColumn(Modifier.fillMaxSize().padding(12.dp),
            horizontalAlignment = Alignment.CenterHorizontally) 
            //Header for first inner list
            item 
                Text(text = "List of numbers:", style = MaterialTheme.typography.h5)
            
            // First, scrollable, inner list
            item 
                // Note the important height modifier.
                LazyColumn(Modifier.height(100.dp))
                    val numbersList = (0 .. 400 step 4).toList()
                    itemsIndexed(numbersList)  index, multipleOf4 ->
                        Text(text = "$multipleOf4", style = TextStyle(fontSize = 22.sp, color = Color.Blue))
                    
                
            

        // Header for second inner list
        item 
            Text(text = "List of letters:", style = MaterialTheme.typography.h5)
        
        // Second, scrollable, inner list
        item 
            // Note the important height modifier.
            LazyColumn(Modifier.height(200.dp)) 
                val lettersList = ('a' .. 'z').toList()
                itemsIndexed(lettersList)  index, letter ->
                    Text(text = "$letter", style = TextStyle(color = Color.Blue, fontSize = 22.sp))
                
            
        
    

【讨论】:

你能解释一下接受的答案和你的答案有什么区别吗? 与接受的答案不同,我的答案依赖于 .height() 修饰符来避免“java.lang.IllegalStateException:不允许在相同方向的布局中嵌套可滚动,如 ScrollableContainer 和 LazyColumn... “ 错误。另外,我的回答解决了同方向嵌套滚动的情况。最后,在我的示例中,底部列表可以独立于顶部列表滚动。感谢您的澄清评论:)! 哦,好的。感谢您的澄清。我认为这与接受的答案相同。 @CherifDiallo:哇,这是有用的澄清。您能否将其编辑到您的答案中,以便未来的读者不会对差异感到困惑?谢谢。

以上是关于Jetpack compose 中的 [NestedScrollView + RecyclerView] 或 [Nested RecyclerView (Recycler inside another的主要内容,如果未能解决你的问题,请参考以下文章

JetPack Compose 基础(3)Compose 中的主题

Jetpack Compose中的Canvas

Jetpack Compose 中的作用域状态

Jetpack Compose中的副作用Api

Jetpack Compose 中的状态管理

Jetpack Compose 中的状态管理