How to make UICollectionView with infinite paging?

I have a UICollectionView with 6 pages, and swapping is enabled and UIPageControl. I want that when I come to the last page, if I drag to the right, the UICollectionView reloads from the first page without any problems.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender { // The key is repositioning without animation if (collectionView.contentOffset.x == 0) { // user is scrolling to the left from image 1 to image 10. // reposition offset to show image 10 that is on the right in the scroll view [collectionView scrollRectToVisible:CGRectMake(collectionView.frame.size.width*(pageControl.currentPage-1),0,collectionView.frame.size.width,collectionView.frame.size.height) animated:NO]; } else if (collectionView.contentOffset.x == 1600) { // user is scrolling to the right from image 10 to image 1. // reposition offset to show image 1 that is on the left in the scroll view [collectionView scrollRectToVisible:CGRectMake(0,0,collectionView.frame.size.width,collectionView.frame.size.height) animated:NO]; } pageControlUsed = NO; } 

This does not work as I want. What can I do?

+4
source share
3 answers

I use the Street Scroller sample to create an infinite scroller for images. This works fine until I want to set pagingEnabled = YES; I tried setting around recenterIfNecessary code and finally realized that it was contentOffset.x, which should correspond to the subview frame that I want to see when paging stops. This really will not work in recenterIfNecessary, since you have no way of knowing that it will be called from layoutSubviews. If you configure it correctly, a subview may pop out from under your finger. I am setting up in scrollViewDideEndDecelerating. So far I have not had problems with fast scrolling. It will work and simulate swap, even if pagingEnabled is NO, but with YES it looks more natural.

 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [super scrollViewDidEndDecelerating:scrollView]; CGPoint currentOffset = [self contentOffset]; // find the subview that is the closest to the currentOffset. CGFloat closestOriginX = 999999; UIView *closestView = nil; for (UIView *v in self.visibleImageViews) { CGPoint origin = [self.imageContainerView convertPoint:v.frame.origin toView:self]; CGFloat distanceToCurrentOffset = fabs(currentOffset.x - origin.x); if (distanceToCurrentOffset <= closestOriginX) { closestView = v; closestOriginX = distanceToCurrentOffset; } } // found the closest view, now find the correct offset CGPoint origin = [self.imageContainerView convertPoint:closestView.frame.origin toView:self]; CGPoint center = [self.imageContainerView convertPoint:closestView.center toView:self]; CGFloat offsetX = currentOffset.x - origin.x; // adjust the centers of the subviews [UIView animateWithDuration:0.1 animations:^{ for (UIView *v in self.visibleImageViews) { v.center = [self convertPoint:CGPointMake(v.center.x+offsetX, center.y) toView:self.imageContainerView]; } }]; 

}

+1
source

Here is what I got for my UICollectionView (horizontal scrolling such as UIPickerView):

 @implementation UIInfiniteCollectionView - (void) recenterIfNecessary { CGPoint currentOffset = [self contentOffset]; CGFloat contentWidth = [self contentSize].width; // don't just snap to center, since this might be done in the middle of a drag and not aligned. Make sure we account for that offset CGFloat offset = kCenterOffset - currentOffset.x; int delta = -round(offset / kCellSize); CGFloat shift = (offset + delta * kCellSize); offset += shift; CGFloat distanceFromCenter = fabs(offset); // don't always recenter, just if we get too far from the center. Eliza recommends a quarter of the content width if (distanceFromCenter > (contentWidth / 4.0)) { self.contentOffset = CGPointMake(kCenterOffset, currentOffset.y); // move subviews back to make it appear to stay still for (UIView *subview in self.subviews) { CGPoint center = subview.center; center.x += offset; subview.center = center; } // add the offset to the index (unless offset is 0, in which case we'll assume this is the first launch and not a mid-scroll) if (currentOffset.x > 0) { int delta = -round(offset / kCellSize); // MODEL UPDATE GOES HERE } } } - (void) layoutSubviews { // called at every frame of scrolling [super layoutSubviews]; [self recenterIfNecessary]; } @end 

Hope this helps someone.

+2
source

I have not used UICollectionView to scroll endlessly, but when you do this using UIScrollView, you first adjust the offset of your content (instead of using scrollRectToVisible) to the right place. Then you look at each subtitle in your scroller and adjust your coordinates to the right or left, depending on the user's scroll direction. Finally, if either end extends beyond what you want them to be, move them to the other end. This is a very good Apple WWDC video on how endless scrolling can be found here: http://developer.apple.com/videos/wwdc/2012/

+1
source

All Articles