Requires iOS 8+
Say you want 3 cells per row in portrait, but 4 cells in landscape. First calculate the cell dimensions based on the screen width and a padding of 5.
var cellsPerRow:CGFloat = 3
let cellPadding:CGFloat = 5
extension ViewController : UICollectionViewDelegateFlowLayout {
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let widthMinusPadding = UIScreen.mainScreen().bounds.width - (cellPadding + cellPadding * cellsPerRow)
let eachSide = widthMinusPadding / cellsPerRow
return CGSize(width: eachSide, height: eachSide)
}
}The above assumes you set Min Spacing and Section Insets values all to 5 in the Storyboard.
traitCollectionDidChange gets called on rotation. On iPhone, verticalSizeClass changes from .Regular (portrait) to .Compact (landscape). Don't bother checking horizontalSizeClass because it's always .Compact.
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
cellsPerRow = (traitCollection.verticalSizeClass == .Compact) ? 4 : 3
collectionView.reloadData()
}
traitCollectionDidChange(previousTraitCollection :)won't be called on iPad when it is rotated, because size class is.regularin both portrait and landscape orientations. There'sviewWillTransition(to:with:)that will be called whenever collection view size changes.Also you shouldn't use
UIScreen.mainScreen().boundsif your app supports multitasking as it might not occupy the whole screen, better usecollectionView.frame.widthfor that.