Issue with pagination in UICollectionView when ori

2019-03-21 10:48发布

enter image description here enter image description here
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.

3条回答
祖国的老花朵
2楼-- · 2019-03-21 11:14

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)

}
查看更多
放荡不羁爱自由
3楼-- · 2019-03-21 11:18
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];
}
查看更多
Root(大扎)
4楼-- · 2019-03-21 11:28

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.

查看更多
登录 后发表回答