Keeping the contentOffset in a UICollectionView while rotating Interface Orientation

cocoa-touch, ios, objective-c, uicollectionview, uiscrollview

Solution

You can either do this in the view controller:

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

    guard let collectionView = collectionView else { return }
    let offset = collectionView.contentOffset
    let width = collectionView.bounds.size.width

    let index = round(offset.x / width)
    let newOffset = CGPoint(x: index * size.width, y: offset.y)

    coordinator.animate(alongsideTransition: { (context) in
        collectionView.reloadData()
        collectionView.setContentOffset(newOffset, animated: false)
    }, completion: nil)
}

Or in the layout itself: https://stackoverflow.com/a/54868999/308315

Problem

I'm trying to handle interface orientation changes in a UICollectionViewController. What I'm trying to achieve is, that I want to have the same contentOffset after an interface rotation. Meaning, that it should be changed corresponding to the ratio of the bounds change. Starting in portrait with a content offset of {bounds.size.width * 2, 0} … … should result to the content offset in landscape also with {bounds.size.width * 2, 0} (and vice versa). Calculating the new offset is not the problem, but don't know, where (or when) to set it, to get a smooth animation. What I'm doing so fare is invalidating the layout in `willRotateToInterfaceOrientation:duration:` and resetting the content offset in `didRotateFromInterfaceOrientation:`: ``` - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration; { self.scrollPositionBeforeRotation = CGPointMake(self.collectionView.contentOffset.x / self.collectionView.contentSize.width, self.collectionView.contentOffset.y / self.collectionView.contentSize.height); [self.collectionView.collectionViewLayout invalidateLayout]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation; { CGPoint newContentOffset = CGPointMake(self.scrollPositionBeforeRotation.x * self.collectionView.contentSize.width, self.scrollPositionBeforeRotation.y * self.collectionView.contentSize.height); [self.collectionView newContentOffset animated:YES]; } ``` This changes the content offset after the rotation. How can I set it during the rotation? I tried to set the new content offset in `willAnimateRotationToInterfaceOrientation:duration:` but this results into a very strange behavior. An example can be found in my Project on GitHub.

Original source

Related problems