I have a UICollectionView
in my view controller defined as follows:
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = Constants.minimumLineSpacing
layout.minimumInteritemSpacing = Constants.minimumInteritemSpacing
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = Constants.backgroundColor
collectionView.contentInset = Constants.collectionViewContentInsets
collectionView.refreshControl = refreshControl
I set the cell size in sizeForItemAt
:
func collectionView(
_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath
) -> CGSize {
let collectionViewHorizontalInset = Constants.collectionViewInsets.left Constants.collectionViewInsets.right
let cellWidth = isPortrait
? (screenSize.width - collectionViewHorizontalInset - Constants.minimumInteritemSpacing) / 2.0
: (screenSize.width - collectionViewHorizontalInset - Constants.minimumInteritemSpacing * 2.0) / 3.0
return CGSize(width: cellWidth, height: Constants.cellHeight)
}
with sceenSize as follows:
private var screenSize: CGSize {
view.bounds.size
}
The property isPortrait
keeps track of the orientation, in viewDidLoad
:
isPortrait = view.bounds.size.width < view.bounds.size.height
and in viewWillTransition
I have the following:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
isPortrait = size.width < size.height
collectionView.collectionViewLayout.invalidateLayout()
}
When I rotate the device it seems that it is getting the incorrect screen size and therefore calculating an incorrect width for the cells. e.g If I load the app in landscape there will be 3 cell per row which is correct. However if I then rotate to portrait and back to landscape there will be 4 cells per row which is incorrect.
What am I doing wrong here? How can I get the correct screen size after the rotation?
CodePudding user response:
This helped me lot a earlier to solve your issue. Details are added in the comments.
class CollectionViewFlowLayout: UICollectionViewFlowLayout{
/// The default implementation of this method returns false.
/// Subclasses can override it and return an appropriate value
/// based on whether changes in the bounds of the collection
/// view require changes to the layout of cells and supplementary views.
/// If the bounds of the collection view change and this method returns true,
/// the collection view invalidates the layout by calling the invalidateLayout(with:) method.
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return (self.collectionView?.bounds ?? newBounds) != newBounds
}
}
CodePudding user response:
Answering my own question with what worked for me:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate { _ in
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
Seems that the key was to use coordinator.animate
, that way the screen size would be correct when sizeForItemAt
does its calculation.