UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置
生活随笔
收集整理的這篇文章主要介紹了
UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一個UICollectionView有好多個cell,滑動一下,誰也不知道會停留在哪個cell,滑的快一點,就會多滑一段距離,反之則會滑的比較近,這正是UIScrollview用戶體驗好的地方。 如果想要UICollectionView停留到某個cell的位置,可以用 - (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated; 這個方法,還能用scrollPosition這個參數控制cell具體停留在上下左右中到底哪個位置。 那么問題來了:如果我只是隨便滑了一下,我也不知道它會停在位于哪個indexPath的cell上,但不管它停在哪個cell上,我都希望這個cell剛好在屏幕中間,應該怎么辦呢?(這個場景在coverFlow的效果里比較常見) 之前知道的做法是: 在scrollViewDidEndDecelerating或其他delegate方法里,通過當前 contentOffset 計算最近的整數頁及其對應的 contentOffset,然后通過動畫移動到這個位置。 但是這個做法有問題,就是動畫不連貫,完全沒有“剛好停到那里”的感覺。 今天在想有沒有其他更好的辦法時,突然發現一個之前從來沒用功的方法: - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset NS_AVAILABLE_IOS(5_0); 一看這參數名,再看看這文檔,真是讓人喜不自禁吶!這不就是讓scrollView“剛好停到某個位置”的方法嘛!!!(系統5.0就提供了,現在才看到。。。。。。) targetContentOffset 是個指針,可以修改這個參數的值,讓scrollView最終停止在目標位置。 (2016年12月7日更新) 注意:scrollView的pagingEnable屬性必須為NO時這個方法才會被調用。 感謝@?ZeroOnet?評論中指出,這個方法在pagingEnable==YES的時候也會調用; 但是pagingEnable的效果會覆蓋這個方法的效果,達不到我們想要的“剛好停到指定位置的效果”,所以還是需要注意將pagingEnable設置為NO! 例: - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
??? CGPoint originalTargetContentOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y);
??? CGPoint targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2, CGRectGetHeight(self.collectionView.bounds) / 2);
??? NSIndexPath *indexPath = nil;
??? NSInteger i = 0;
??? while (indexPath == nil) {
??????? targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2 + 10*i, CGRectGetHeight(self.collectionView.bounds) / 2);
??????? indexPath = [self.collectionView indexPathForItemAtPoint:targetCenter];
??????? i++;
??? }
??? self.selectedIndex = indexPath;
??? //這里用attributes比用cell要好很多,因為cell可能因為不在屏幕范圍內導致cellForItemAtIndexPath返回nil
??? UICollectionViewLayoutAttributes *attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];
??? if (attributes) {
??????? *targetContentOffset = CGPointMake(attributes.center.x - CGRectGetWidth(self.collectionView.bounds)/2, originalTargetContentOffset.y);
??? } else {
??????? DLog(@"center is %@; indexPath is {%@, %@}; cell is %@",NSStringFromCGPoint(targetCenter), @(indexPath.section), @(indexPath.item), attributes);
??? }
??? } 這樣scrollView就會逐漸減速,最終停止在itemCenterOffsetWithOriginalTargetContentOffset方法算出來的位置上了,效果杠杠的~ 本來以為這個方法沒多少人知道,結果百度一搜,發現原來已經有大神寫過詳細的文章了(http://tech.glowing.com/cn/practice-in-uiscrollview/),這個就當記錄一下吧 另外發現一個直接用NSObject就實現類似效果的庫:https://github.com/nicklockwood/iCarousel ? 乍看之下沒看懂。。。等有空再仔細研究 更新(2015-06-19) 原來UICollectionViewLayout已經提供了兩個方法可以實現這個功能: - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset NS_AVAILABLE_IOS(7_0); 效果與上面的delegate方法完全一樣,不過這個是UICollectionViewLayout的方法,需要在自己的layout子類里重載。 好處是:這樣就不用再在viewController里寫scrollView的delegate方法了,viewController更加簡潔;跟布局相關的代碼都轉移到了layout的類中? ?
??? CGPoint originalTargetContentOffset = CGPointMake(targetContentOffset->x, targetContentOffset->y);
??? CGPoint targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2, CGRectGetHeight(self.collectionView.bounds) / 2);
??? NSIndexPath *indexPath = nil;
??? NSInteger i = 0;
??? while (indexPath == nil) {
??????? targetCenter = CGPointMake(originalTargetContentOffset.x + CGRectGetWidth(self.collectionView.bounds)/2 + 10*i, CGRectGetHeight(self.collectionView.bounds) / 2);
??????? indexPath = [self.collectionView indexPathForItemAtPoint:targetCenter];
??????? i++;
??? }
??? self.selectedIndex = indexPath;
??? //這里用attributes比用cell要好很多,因為cell可能因為不在屏幕范圍內導致cellForItemAtIndexPath返回nil
??? UICollectionViewLayoutAttributes *attributes = [self.collectionView.collectionViewLayout layoutAttributesForItemAtIndexPath:indexPath];
??? if (attributes) {
??????? *targetContentOffset = CGPointMake(attributes.center.x - CGRectGetWidth(self.collectionView.bounds)/2, originalTargetContentOffset.y);
??? } else {
??????? DLog(@"center is %@; indexPath is {%@, %@}; cell is %@",NSStringFromCGPoint(targetCenter), @(indexPath.section), @(indexPath.item), attributes);
??? }
??? } 這樣scrollView就會逐漸減速,最終停止在itemCenterOffsetWithOriginalTargetContentOffset方法算出來的位置上了,效果杠杠的~ 本來以為這個方法沒多少人知道,結果百度一搜,發現原來已經有大神寫過詳細的文章了(http://tech.glowing.com/cn/practice-in-uiscrollview/),這個就當記錄一下吧 另外發現一個直接用NSObject就實現類似效果的庫:https://github.com/nicklockwood/iCarousel ? 乍看之下沒看懂。。。等有空再仔細研究 更新(2015-06-19) 原來UICollectionViewLayout已經提供了兩個方法可以實現這個功能: - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity; - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset NS_AVAILABLE_IOS(7_0); 效果與上面的delegate方法完全一樣,不過這個是UICollectionViewLayout的方法,需要在自己的layout子類里重載。 好處是:這樣就不用再在viewController里寫scrollView的delegate方法了,viewController更加簡潔;跟布局相關的代碼都轉移到了layout的類中? ?
轉載于:https://www.cnblogs.com/Phelthas/p/4584645.html
總結
以上是生活随笔為你收集整理的UIScrollView的delegate方法妙用之让UICollectionView滑动到某个你想要的位置的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 学习笔记10
- 下一篇: 系统怎么刻录到u盘 系统教程:U盘刻录方