Home > database >  Screen size incorrect after UICollectionView rotation
Screen size incorrect after UICollectionView rotation

Time:06-06

I have a UICollectionView in my view controller defined as follows:

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = Constants.minimumLineSpacing
layout.minimumInteritemSpacing = Constants.minimumInteritemSpacing

let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = Constants.backgroundColor
collectionView.contentInset = Constants.collectionViewContentInsets

collectionView.refreshControl = refreshControl

I set the cell size in sizeForItemAt:

func collectionView(
    _ collectionView: UICollectionView,
    layout collectionViewLayout: UICollectionViewLayout,
    sizeForItemAt indexPath: IndexPath
) -> CGSize {
    let collectionViewHorizontalInset = Constants.collectionViewInsets.left   Constants.collectionViewInsets.right

    let cellWidth = isPortrait
        ? (screenSize.width - collectionViewHorizontalInset - Constants.minimumInteritemSpacing) / 2.0
        : (screenSize.width - collectionViewHorizontalInset - Constants.minimumInteritemSpacing * 2.0) / 3.0

    return CGSize(width: cellWidth, height: Constants.cellHeight)
}

with sceenSize as follows:

private var screenSize: CGSize {
    view.bounds.size
}

The property isPortrait keeps track of the orientation, in viewDidLoad:

isPortrait = view.bounds.size.width < view.bounds.size.height

and in viewWillTransition I have the following:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    isPortrait = size.width < size.height
    collectionView.collectionViewLayout.invalidateLayout()
}

When I rotate the device it seems that it is getting the incorrect screen size and therefore calculating an incorrect width for the cells. e.g If I load the app in landscape there will be 3 cell per row which is correct. However if I then rotate to portrait and back to landscape there will be 4 cells per row which is incorrect.

What am I doing wrong here? How can I get the correct screen size after the rotation?

CodePudding user response:

This helped me lot a earlier to solve your issue. Details are added in the comments.

class CollectionViewFlowLayout: UICollectionViewFlowLayout{
    
    /// The default implementation of this method returns false.
    /// Subclasses can override it and return an appropriate value
    /// based on whether changes in the bounds of the collection
    /// view require changes to the layout of cells and supplementary views.
    /// If the bounds of the collection view change and this method returns true,
    /// the collection view invalidates the layout by calling the invalidateLayout(with:) method.
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        
        return (self.collectionView?.bounds ?? newBounds) != newBounds
    }
}

CodePudding user response:

Answering my own question with what worked for me:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    coordinator.animate { _ in
        self.collectionView.collectionViewLayout.invalidateLayout()
    }
}

Seems that the key was to use coordinator.animate, that way the screen size would be correct when sizeForItemAt does its calculation.

  • Related