I'm preparing a GridView with all orientation support (height & width resizing) and paging enabled.
In my sample in have taken a 3*3 Grid and to show it like that I have added some dummy transparent cell at the last page.
The issue is when I'm at last page and there I'm changing my orientation from landscape to portrait the pagination doesn't work.
I have used this code in willRotateToInterfaceOrientation
:
CGPoint scrollTo = CGPointMake(self.frame.size.width * mPageControl.currentPage, 0);
[self setContentOffset:scrollTo animated:YES];
But still page moves to a page before the last page when going from landscape to portrait and while changing portrait to landscape it works fine.
Had the same problem, my UICollectionView was paginated, when I scrolled to page 2 in portrait mode and then switched to landscape, the content offset would be set to (72, 0), and this would persist.
The controller was registered for orientation changes where it invalidated the layout, but setting the offset in there didn't help.
What did help was setting the offset inside the layout class' prepareForLayout method. I used
self.collectionView.contentOffset =
CGPointMake(ceil(self.collectionView.contentOffset.x/self.collectionView.frame.size.width)*self.collectionView.frame.size.width,
self.collectionView.contentOffset.y);
Ceiling is used because floor would always go back to the previous page (and page 0 always paginates fine).
If you're not using a custom layout, you can still subclass flow layout and override that one function.
I manage to solve this by setting notification when screen orientation changes and reloading cell which set itemsize according to screen orientation and setting indexpath to previous cell. This does work with flowlayout too. Here is the code i wrote:
var cellWidthInLandscape: CGFloat = 0 {
didSet {
self.collectionView.reloadData()
}
}
var lastIndex: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
collectionView.dataSource = self
collectionView.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
cellWidthInLandscape = UIScreen.main.bounds.size.width
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func rotated() {
// Setting new width on screen orientation change
cellWidthInLandscape = UIScreen.main.bounds.size.width
// Setting collectionView to previous indexpath
collectionView.scrollToItem(at: IndexPath(item: lastIndex, section: 0), at: .right, animated: false)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
NotificationCenter.default.addObserver(self, selector: #selector(rotated), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
// Getting last contentOffset to calculate last index of collectionViewCell
lastIndex = Int(scrollView.contentOffset.x / collectionView.bounds.width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Setting new width of collectionView Cell
return CGSize(width: cellWidthInLandscape, height: collectionView.bounds.size.height)
}
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
//Ignoring specific orientations
if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || currentOrientation == orientation)
{
return;
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(relayoutLayers) object:nil];
//Responding only to changes in landscape or portrait
currentOrientation = orientation;
[self performSelector:@selector(handleOrientationChange) withObject:nil afterDelay:0];
Then i'm calling a method whenever orientation is changing
-(void)handleOrientationChange
{
CGRect frame = self.frame;
frame.origin.x = self.frame.size.width * mPageControl.currentPage;
frame.origin.y = 0;
[self scrollRectToVisible:frame animated:YES];
}