2

I would like to have the first section's cells be the full width of the collection view and the second section be half of the width. On startup, the cells don't respect the given width although the height seems to be respected. After a couple of seconds, the collection view is reloaded and most of the time it sets the cells to the correct sizes. When the phone's orientation changes to landscape, the cells are drawn in the incorrect sizes again.

I've tried using UICollectionViewDelegateFlowLayout and the sizeForItemAt delegate function to set the cell sizes but they don't follow the given sizes even if the function is being called.

Currently, I am setting section insets and then calculating the remaining available width for the cells in the collection view's bounds, afterward I divide the width by the number of cells per row.

class HomeCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    let sectionInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

    override func viewDidLoad() {
        super.viewDidLoad()

        self.collectionView?.contentInsetAdjustmentBehavior = .always
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: collectionView.frame.width, height: 44)
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        return self.sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return self.sectionInsets.left
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        var numberOfItemsPerRow: CGFloat = 1
        var height: CGFloat = 0

        switch indexPath.section {
        case 0:
            numberOfItemsPerRow = 1
            height = 97
        case 1:
            numberOfItemsPerRow = 2
            height = 126
        default:
            break
        }

        let padding = self.sectionInsets.left * (numberOfItemsPerRow + 1)
        let availableWidth = collectionView.bounds.size.width - padding
        let width = availableWidth / numberOfItemsPerRow

        return CGSize(width: width, height: height)
    }
}

This results in the cells to be sized incorrectly as in the following image. Incorrect Example Image

The only time they are sized correctly is after the collection view is reloaded. Correct Example Image

Also, when the phone turns to landscape it displays it incorrectly. Incorrect Landscape Example Image

To conclude my issue, the first section's cells should always take 100% of the available width. If possible it would be very nice if they would have an automatic height. I've tried using UICollectionViewFlowLayout.automaticSize.height but I don't think that would work. For the second section, it needs to always take 50% of the available width.

2 Answers2

9

If you're using Storyboard to create the CollectionView.

I thought I had to invalidateLayout(). It turns out there's a weird bug with iOS 13.

you have to create your own UICollectionViewFlowLayout. Call something like this in your viewDidLoad()


        collectionView.collectionViewLayout = {
            let flowLayout = UICollectionViewFlowLayout()
            flowLayout.scrollDirection = .horizontal
            return flowLayout
        }()
Dot Freelancer
  • 4,083
  • 3
  • 28
  • 50
blyscuit
  • 616
  • 7
  • 12
  • Surely you mean iOS 13, right? ;) But yeah, that did it for my console UICollectionViewFlowLayoutBreakForInvalidSizes warnings. – Ivan Jul 07 '20 at 10:27
  • No biggie, was clear what was meant. Just gave feedback for others reading thread. Cheers. – Ivan Jul 29 '20 at 10:04
3

You must invalidate layout on viewDidLayoutSubviews to re-calculate sizes for cells. I have attached code snippet. Try this one

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews() 
    collectionView.collectionViewLayout.invalidateLayout()
}
bohdans
  • 49
  • 1
  • 4