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.regular
in 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().bounds
if your app supports multitasking as it might not occupy the whole screen, better usecollectionView.frame.width
for that.