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.

  • change text of button and disable button in iOS
  • Printing the view in iOS with Swift
  • Including custom data into iOS crash dumps
  • UIPopover How do I make a popover with buttons like this?
  • UISearchBar on the top of UITableView which can hide but stay close to UINavigationBar
  • How to bold some words in my UITextView using NSMutableAttributedString?
  • 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
    }