UICollectionViewCompositionalLayout: custom grid layout where only one cell has to be bigger than the rest

577 views Asked by At

I'm trying to build a photo grid using UICollectionViewCompositionalLayout where the third picture is shown bigger, all the other pictures should be small.

I've come this far:

enter image description here

The problem is that this layout keeps repeating itself, so now one out of every six pictures is shown bigger, instead of it only happening in the first group.

This is my layout code:

private func createLayout() -> UICollectionViewLayout {
  // Three photos next to eachother
  let tripletItem = NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1 / 3), heightDimension: .fractionalHeight(1)))
  tripletItem.contentInsets = .init(top: 2, leading: 2, bottom: 2, trailing: 2)

  let tripletGroup = NSCollectionLayoutGroup.horizontal(
    layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalWidth(1 / 3)),
    subitems: [tripletItem]
  )

  // Two small photos with a bigger photo next to it
  let mainItem = NSCollectionLayoutItem(
    layoutSize: NSCollectionLayoutSize(
      widthDimension: .fractionalWidth(2 / 3),
      heightDimension: .fractionalHeight(1)
    ))

  mainItem.contentInsets = NSDirectionalEdgeInsets(
    top: 2,
    leading: 2,
    bottom: 2,
    trailing: 2
  )

  let pairItem = NSCollectionLayoutItem(
    layoutSize: NSCollectionLayoutSize(
      widthDimension: .fractionalWidth(1),
      heightDimension: .fractionalHeight(0.5)
    ))

  pairItem.contentInsets = NSDirectionalEdgeInsets(
    top: 2,
    leading: 2,
    bottom: 2,
    trailing: 2
  )

  let pairGroup = NSCollectionLayoutGroup.vertical(
    layoutSize: NSCollectionLayoutSize(
      widthDimension: .fractionalWidth(1 / 3),
      heightDimension: .fractionalHeight(1)
    ),
    subitem: pairItem,
    count: 2
  )

  let mainWithPairGroup = NSCollectionLayoutGroup.horizontal(
    layoutSize: NSCollectionLayoutSize(
      widthDimension: .fractionalWidth(1),
      heightDimension: .fractionalWidth(2 / 3)
    ),
    subitems: [pairGroup, mainItem]
  )

  let nestedGroup = NSCollectionLayoutGroup.vertical(
    layoutSize: NSCollectionLayoutSize(
      widthDimension: .fractionalWidth(1),
      heightDimension: .fractionalWidth(1)
    ),
    subitems: [
      mainWithPairGroup,
      tripletGroup,
    ]
  )

  let section = NSCollectionLayoutSection(group: nestedGroup)
  let layout = UICollectionViewCompositionalLayout(section: section)
  return layout
}

How do I make this so that the first group (mainWithPairGroup) is only used once, and then the tripletGroup repeats over and over?

1

There are 1 answers

1
Hunter Meyer On BEST ANSWER

Your section has two subitems: mainWithPairGroup and tripletGroup. When you have more items than these two subgroups have room for, this group is repeated over and over again. If you want to instead have mainWithPairGroup then unlimited tripletGroup, you could have two sections and change your compositional layout to use a section provider as opposed to a single section. Then in your first section you would just have mainWithPairGroup and in your second section you could just use tripletGroup. The problem with this is you would have to now change your data source methods to allow accommodate the two sections.

If you know the number of items you have at the time of layout creation then you could make a group of tripletGroups that has counts equal to the (numberOfItems - 3) / 3. The -3 comes from the 3 in the mainWithPairGroup and the divided by 3 comes from the number of items in each tripletGroup. Then in your nestedGroup your subitems would be mainWithPairGroup and your group of tripletGroups.

    let groupedTripletGroup = NSCollectionLayoutGroup.vertical(
      layoutSize: .init(
        .fractionalWidth(1),
        .fractionalHeight(1)),
      subitem: tripletGroup, 
      count: (numberOfItems - 3)/3)

    let nestedGroup = NSCollectionLayoutGroup.vertical(
      layoutSize: NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1),
        heightDimension: .fractionalWidth(1)),
      subitems: [
        mainWithPairGroup,
        groupedTripletGroup,
      ]
    )