3
votes

I have a collection view with 6 items and want to display them in a 2 cells per row and 3 rows format. The following code achieves this (as taken from this question: Swift: Collection View not adjusting correctly to change in size) in iPhone format nicely.

However on the any iPad the views layout is correct initially but if the screen is rotated to landscape and then back to portrait then the layout does not fully fit within the view and requires horizontal scrolling to see the second cell (cells width has somehow increased meaning the second cell in each row is partially cut off).

override func viewDidLoad() {
 super.viewDidLoad()
 collectionView.dataSource = self
 collectionView.delegate = self

 flowLayout.scrollDirection = .horizontal
 flowLayout.minimumLineSpacing = 5
 flowLayout.minimumInteritemSpacing = 5
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
   return 6
}


override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
    self.collectionView.collectionViewLayout.invalidateLayout()
}


 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

     if UIDevice.current.orientation.isLandscape {
        let totalWidth = collectionView.frame.width 
        let totalHeight = collectionView.frame.height 

        let heightOfCell = totalHeight / 2
        let numberOfCellsPerRow = 1
        let widthOfCell = CGFloat(Int(totalWidth) / numberOfCellsPerRow)

        return CGSize(width: widthOfCell , height: heightOfCell)

    } else {
        let totalWidth = collectionView.frame.width 
        let totalHeight = collectionView.frame.height 
        let heightOfCell = (totalHeight / 3)

        let numberOfCellsPerRow = 2
        let widthOfCell = CGFloat(Int(totalWidth) / numberOfCellsPerRow)

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

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
    return UIEdgeInsetsMake(0, 5, 0, 5)
}

Before rotation After rotation

1
I can't recreate your problem - I've tried copying and pasting your exact code and when I rotate portrait -> landscape -> portrait, it is exactly the same as it started. Can you maybe show some screenshots to illustrate more clearly what's happening? - Matt Le Fleur
I've added them, this is only happening on the iPad, not iPhone - Ryan Hampton
Have you adjusted anything on the storyboard? This isn't the layout I get after adding a brand new collection view to my scene with your code. - Matt Le Fleur
I left out the insetForSectionAt function which I have now added. Could you show me what yours looks like? - Ryan Hampton
So mine looks like this: imgur.com/a/ZIV0z - obviously you can ignore the styling, I've just set the cell to have a black background in cellForItemAt. In the storyboard, the collection view has constraints of 0 to all edges of the view. - Matt Le Fleur

1 Answers

0
votes

The problem here appears to be that, frame of the view is not updated when 'willRotate' is invoked. Instead try 'didrotate' or add the observer 'NSNotification.Name.UIDeviceOrientationDidChange' and invalidateLayout of collection inside the selector method. Don't forget to remove the observer on deinit().