7

I've successfully been able to create a grid layout using UICollectionViewCompositionalLayout. However, I am unable to find a clever way of ensuring the UICollectionViewCell in each row in the grid are of the same height when their heights are dynamic. i.e. I want the cell to stretch to fill the available space height-wise in the row.

Desired layout:

  • Grid (3 x N)
  • Variable height cells
  • Each cell has the same height in a given row. (uses the max cell height in a row)
  • Small divider line at the bottom of each cell.
+------+--+------+--+------+
|~~~~~~|  |~~~~~~|  |~~~~~~|
|~~~~~~|  |~~~~~~|  |~~~~~~|
|~~~~~~|  |~~~~~~|  |      |
|~~~~~~|  |      |  |      |
--------  -------   --------   <--- divider
+------+--+------+--+------+

Note: The row itself is the correct height but I want the cell content to stretch to fill the available space because I need to insert a small "line-divider" at the bottom of each cell. I thought about using a supplementary view for this but it seemed sort of messy.

Current attempt:

func createLayout() -> UICollectionViewLayout {
    let estimatedHeight: CGFloat = 100

    let item = NSCollectionLayoutItem(
        layoutSize: .init(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(estimatedHeight)),
        supplementaryItems: []
    )

    let groupLayoutSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
                                                 heightDimension: .estimated(estimatedHeight))
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupLayoutSize, subitem: item, count: 3)


    let section = NSCollectionLayoutSection(group: group)
    section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
    section.interGroupSpacing = 10
    let layout = UICollectionViewCompositionalLayout(section: section)
    return layout
}

Result:

+------+--+------+--+------+
|~~~~~~|  |~~~~~~|  |~~~~~~|
|~~~~~~|  |~~~~~~|  |~~~~~~|
|~~~~~~|  |~~~~~~|  --------
|~~~~~~|  --------  
--------    
+------+--+------+--+------+

Sample code: https://github.com/johnliedtke/grid-layout

John Slade
  • 219
  • 1
  • 8
  • I have the same problem. Did you find out how to make the cell content to stretch to fill the available space? – Wilko X Nov 05 '20 at 22:17

1 Answers1

0

NSCollectionLayoutSupplementaryItem subclasses NSCollectionLayoutItem, so you should be able to add it as a subitem of your group. So you'd use

let item = NSCollectionLayoutItem(
        layoutSize: .init(widthDimension: .fractionalWidth(1.0), heightDimension: .fractional(1))
    )

let sup = NSCollectionLayoutSupplementaryItem(
            layoutSize: .init(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(2)),
            elementKind: "LineReusableView",
            containerAnchor: .init(edges: [.bottom])
        )
let threeItemGroup = NSCollectionLayoutGroup.horizontal(layoutSize: groupLayoutSize, subitem: item, count: 3)
let group = NSCollectionLayoutGroup.vertical(layoutSize: layoutGroupSize,subitems: [threeItemGroup,sup])

let section = NSCollectionLayoutSection(group: group)

This should result in you only having one line at the bottom of each group rather than your desired three lines, but you should be able to change how that looks in designing your supplementary view (making it draw 3 distinct lines rather than just 1).

Hunter Meyer
  • 314
  • 1
  • 10
  • This solves the divider issue, but could you perhaps amend your answer by outlining how cells with different, variable heights in one row can be made to have the same height? – Ch Ryder Sep 30 '20 at 06:19
  • Just did, made it so that each individual item uses a fractional height and the group as a whole uses an estimated height, so all items should fill to the size of the group and the group should be as big as the biggest one. – Hunter Meyer Oct 01 '20 at 00:06
  • 1
    This code does not compile. Can you please provide a full working example? – Richard Witherspoon Apr 19 '22 at 00:04