Swift: How to refresh UICollectionView layout after rotation of the device

I used UICollectionView (flowlayout) to build a simple layout.
the width for each cell is set to the width of screen using self.view.frame.width

but when I rotate the device, the cells don’t get updated.

  • UILabel overloading in UICollectionView
  • UICollectionView: current index path for page control
  • iOS Android Material Design Hierarchical Timing using UICollectionView
  • How to remove the margin between two UICollectionView columns
  • UICollectionView Performing Updates using performBatchUpdates
  • UICollectionView insert cells above maintaining position (like Messages.app)
  • enter image description here

    I have found a function, which is called upon orientation change :

    override func willRotateToInterfaceOrientation(toInterfaceOrientation: 
      UIInterfaceOrientation, duration: NSTimeInterval) {
        //code
    }
    

    but I am unable to find a way to update the UICollectionView layout

    The main code is here:

    class ViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout{
    
        @IBOutlet weak var myCollection: UICollectionView!
    
        var numOfItemsInSecOne: Int!
        override func viewDidLoad() {
            super.viewDidLoad()
    
            numOfItemsInSecOne = 8
            // Do any additional setup after loading the view, typically from a nib.
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    
            //print("orientation Changed")
        }
    
        func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
            return 1
        }
    
        func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
            return numOfItemsInSecOne
        }
    
        func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
            let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cellO", forIndexPath: indexPath)
    
            return cell
        }
    
        func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize{
        let itemSize = CGSize(width: self.view.frame.width, height: 100)
        return itemSize
        }}
    

    6 Solutions Collect From Internet About “Swift: How to refresh UICollectionView layout after rotation of the device”

    Add this function:

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews() 
        myCollection.collectionViewLayout.invalidateLayout()
    }
    

    When you change the orientation, this function would be called.

    The better option is to call invalidateLayout() instead of reloadData() because it will not force recreation of the cells, so performance will be slightly better:

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews() 
        myCollection.collectionViewLayout.invalidateLayout()
    }
    

    Also you can invalidate it in this way.

    - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
        [self.collectionView.collectionViewLayout invalidateLayout]; 
    }
    

    you can update your UICollectionView Layout by using

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        if isLandscape {
            return CGSizeMake(yourLandscapeWidth, yourLandscapeHeight)
        }
        else {
            return CGSizeMake(yourNonLandscapeWidth, yourNonLandscapeHeight)
        }
    }
    

    to update UICollectionViewLayout traitCollectionDidChange method might be used as well:

    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
    
        guard let previousTraitCollection = previousTraitCollections else {
            return
        }
        collectionView?.collectionViewLayout.invalidateLayout()
    }
    

    The viewWillLayoutSubviews() did not work for me. Neither did viewDidLayoutSubviews(). Both made the app go into an infinite loop which I checked using a print command.

    One of the ways that do work is

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    // Reload here
    }