Search code examples
scrolluicollectionviewuicollectionviewcompositionallayout

Can't scroll properly using UICollectionViewCompositionalLayout and nested group


Here's the layout I'm trying to achieve. I'm trying to achieve a 2 rows by x items grid using compositional layout. Each row is a group that contains x items align horizontally. Both row groups are nested in a vertical group. The section contains the vertical group and allows a horizontal group. I want to display only 2 items in every row in the cell's viewport and have a preview of the next item.

After many tries, I was successful in adding the items in this order:

| 1 | 2 | 3 |

| 4 | 5 |

The problem comes when I try to scroll to view the third item. I can't see it fully like if the last item on the row wasn't adding width to the group.

Here's the code:

        let numberOfItemsOnTheFirstRow = Int(ceil(Double(favoritesCount) / 2))
        
        let itemSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(0.5),
            heightDimension: .fractionalHeight(1)
        )
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        
        let groupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(0.90),
            heightDimension: .fractionalHeight(0.5)
        )
        let rowGroup: NSCollectionLayoutGroup
        if #available(iOS 16.0, *) {
            rowGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, repeatingSubitem: item, count: numberOfItemsOnTheFirstRow)
        } else {
            rowGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count:numberOfItemsOnTheFirstRow)
        }
        rowGroup.interItemSpacing = .fixed(16)
        let containerGroupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1),
            heightDimension: .estimated(290)
        )
        let containerGroup = NSCollectionLayoutGroup.vertical(layoutSize: containerGroupSize, subitems: [rowGroup, rowGroup])
        containerGroup.interItemSpacing = .fixed(16)
  
        let section = NSCollectionLayoutSection(group: containerGroup)
        section.contentInsets = NSDirectionalEdgeInsets(top: 16, leading: 16, bottom: 16, trailing: 16)
        section.interGroupSpacing = 16
        section.addingFavoritesSectionHeader()
        section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
        
        return section

Solution

  • I had two problems with my code. First, there was an error in cellForRowAtIndexPath (not shown in my question). There was a mismatch with indexPaths.

    Second, here's the code the fixed the scroll:

           let itemSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(0.5),
                heightDimension: .fractionalHeight(1.0)
            )
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            item.contentInsets = NSDirectionalEdgeInsets(top: 8.0, leading: 8.0, bottom: 8.0, trailing: 8.0)
            
            let groupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalHeight(1.0)
            )
            let nestedGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            
            let containerGroupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(0.9),
                heightDimension: .estimated(300)
            )
            let containerGroup = NSCollectionLayoutGroup.vertical(
                layoutSize: containerGroupSize,
                subitem: nestedGroup,
                count: 2
            )
            
            let section = NSCollectionLayoutSection(group: containerGroup)
            section.contentInsets = NSDirectionalEdgeInsets(top: 8.0, leading: 8.0, bottom: 8.0, trailing: 8.0)
            section.addingFavoritesSectionHeader()
            section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
            
            return section