I gave your UICollectionView a background of orange and ran your code and got similar results:

I noticed few things
- From this I could conclude the UICollectionView seems to be set up and working well on rotation, probably due to auto layout so I feel the issue is more to do with the layout code.
- I also noticed when you start scrolling, the View fixes itself to what you want
- Finally, I added one line of code to your
func relayoutCollectionView(with size: CGSize)
function to see what the dimensions are when you want update the layout calculations and columns
func relayoutCollectionView(with size: CGSize) {
collectionView.collectionViewLayout.shouldInvalidateLayout(forBoundsChange: CGRect(x: 0,
y: 0,
width: size.width,
height: size.height))
collectionView.setCollectionViewLayout(createFlowLayout(),
animated: true,
completion: nil)
collectionView.collectionViewLayout.invalidateLayout()
// I added this line
print("Collection View Width: \(collectionView.frame.size.width), Collection View Height: \(collectionView.frame.size.height)")
}
When I turned from portrait to landscape, the output printed was Collection View Width: 810.0, Collection View Height: 1080.0
which does not seem to be right.
So from this I assume that it is too early for invalidateLayout to be called to get the right calculations.
When I do something like this from a UIViewController, I will make invalidateLayout()
call from viewWillLayoutSubviews()
In your case, what I tried and worked was adding the similar override func layoutSubviews()
in your class CollectionView: UIView
override func layoutSubviews() {
super.layoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
I removed relayoutCollectionView
from your func relayoutCollectionView
Now it seems to work for the first time as well although I can still not explain why your current works every other time except for the first time.