2
I want the cell to horizontaly Hug its content

I am using UICollectionViewCompositionalLayout in horizontal mode and with widthDimension: .estimated(100) which should calculate the content size

but the width of cell / group is NOT calculated by the content size at all and is set to the estimated values as it would be an absolute value

Even adding a width constraint to the label doesn't affect the cells size

Is this expected behavior? When yes, then why? and how to get the desired result?

enter image description here

enter image description here

class LabelCell: UICollectionViewCell {
    @IBOutlet weak var label: UILabel!
}

class ViewController: UIViewController, UICollectionViewDataSource {

    func buildLayout() -> UICollectionViewCompositionalLayout {

        let itemSize = NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .absolute(32))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .estimated(100), heightDimension: .absolute(32))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)

        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = 10

        let configuration = UICollectionViewCompositionalLayoutConfiguration()
        configuration.scrollDirection = .horizontal
        return UICollectionViewCompositionalLayout(section: section, configuration: configuration)

    }

    @IBOutlet weak var collectionView: UICollectionView!

    let items = ["1", "12", "12345", "123456789"]

    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.collectionViewLayout = buildLayout()
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let c = collectionView.dequeueReusableCell(withReuseIdentifier: "LabelCell", for: indexPath) as! LabelCell
        c.label.text = items[indexPath.row]
        return c
    }
}
Peter Lapisu
  • 19,915
  • 16
  • 123
  • 179
  • Try giving the height and width of item like fractionalHeight(1) and fractionalWidth(1) this might be a problem with the layout. – Nisarg Shah Apr 15 '20 at 15:54

1 Answers1

7

To size your cells correctly, change:

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)

To this:

let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

I'm unsure why this change is necessary, as these lines appear to say the same thing. That said, it will work provided your collection view cell specifies the actual cell size by overriding sizeThatFits(_:), preferredLayoutAttributesFitting(_:), using Auto Layout, etc.

For what it's worth, the documentation for the first function signature says:

Specifies a group that will have N items equally sized along the horizontal axis.

The comment for the second function signature makes no such claims about equally sized items. It says:

Specifies a group that will repeat items until available horizontal space is exhausted.

JWK
  • 3,345
  • 2
  • 19
  • 27
  • Yes, using `subitems: [item]` it behaved right!... But even giving the docu "Specifies a group that will have N items equally sized along the horizontal axis." N == 1, so i dont see why all items should be sized equaly... It looks like everytime you use the count: variant, no matter the N, they are sized equaly – Peter Lapisu Apr 30 '20 at 16:26
  • 1
    I agree. This feels like unexpected behavior. I might file a bug report with Apple. – JWK Apr 30 '20 at 20:46