Custom UIScrollView paging with scrollViewWillEndDragging
You can implement custom paging with this code:
- (float) pageWidth { return ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).itemSize.width + ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).minimumInteritemSpacing;}- (void) scrollViewWillBeginDragging:(UIScrollView *)scrollView { CGFloat pageWidth = self.collectionView.frame.size.width + 10 /* Optional Photo app like gap between images. Or use [self pageWidth] in case if you want the next page be also visible */; _currentPage = floor((self.collectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1; NSLog(@"Dragging - You are now on page %i", _currentPage);}- (void) scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset { CGFloat pageWidth = self.collectionView.frame.size.width + 10; // [self pageWidth] int newPage = _currentPage; if (velocity.x == 0) { // slow dragging not lifting finger newPage = floor((targetContentOffset->x - pageWidth / 2) / pageWidth) + 1; } else { newPage = velocity.x > 0 ? _currentPage + 1 : _currentPage - 1; if (newPage < 0) newPage = 0; if (newPage > self.collectionView.contentSize.width / pageWidth) newPage = ceil(self.collectionView.contentSize.width / pageWidth) - 1.0; } NSLog(@"Dragging - You will be on %i page (from page %i)", newPage, _currentPage); *targetContentOffset = CGPointMake(newPage * pageWidth, targetContentOffset->y);}
Of course you must set pagingEnabled = NO._currentPage is a class iVar.Thanks to http://www.mysamplecode.com/2012/12/ios-scrollview-example-with-paging.html for pointing the right way.
SWIFT 3
With a demo here https://github.com/damienromito/CollectionViewCustom
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { let pageWidth = Float(itemWidth + itemSpacing) let targetXContentOffset = Float(targetContentOffset.pointee.x) let contentWidth = Float(collectionView!.contentSize.width ) var newPage = Float(self.pageControl.currentPage) if velocity.x == 0 { newPage = floor( (targetXContentOffset - Float(pageWidth) / 2) / Float(pageWidth)) + 1.0 } else { newPage = Float(velocity.x > 0 ? self.pageControl.currentPage + 1 : self.pageControl.currentPage - 1) if newPage < 0 { newPage = 0 } if (newPage > contentWidth / pageWidth) { newPage = ceil(contentWidth / pageWidth) - 1.0 } } let point = CGPoint (x: CGFloat(newPage * pageWidth), y: targetContentOffset.pointee.y) targetContentOffset.pointee = point}
I was able to run a quick test and got this to correctly fire and make my object stop as desired. I did this using the following simple test:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{ targetContentOffset->x = scrollView.contentOffset.x - 10; }
It seems that this method is likely not the issue in your code, but it is more likely that your 'goodOffsetX' is not correctly calculating a valid value to stop at.