在最近公司项目需求,要求实现类似于腾讯视频轮播器的效果,另外需要加上缩放效果,先上实现的效果图
定时器效果
手动拖拽效果
手动拖拽的时候可以看到随着拖动的操作,图片有个放大的效果,以上就是所要实现的最终效果。
可能看到这里,你会想到 UICollectionView
,自定义布局,每次滑动结束的时候,将距离屏幕中心位置最近的Item 显示在中间,然后将显示在屏幕中的 Item 进行设置 transform
属性。
在一开始看到这个需求的时候,也没有考虑到这么多,认为一个UICollectionView
就能搞定这个需求。可是当自己把自定义布局实现了,然后鼠标随手一拽,速度一块,发现有多个 Item 已经随着滚动过去了,这明显不能满足需求,如果将pageEnable
属性设置为 YES,虽然可以不让多个 Item 滚动过去,但是UICollectionView
的contentOffset
又不正确,默认的分页宽度为UICollectionView
的宽度。于是在网上找到方案:第一种是将 UIScrollView
的宽度设置为我们想要的每页的偏移宽度,然后将UIScrollView
的clipsToBounds
设置为 NO,这样每次滑动就能达到我们想要的偏移量。第二种是完全自定义分页宽度。
先说说第一种方法:
在将UICollectionView
的 frame
设置为想要的偏移量大小时,因为复用机制,每次滑出 collectionView
范围时,就被回收了,而需求是要显示三张图片,于是转战UIScrollView
,暂时不实现缩放效果。一开始在scrollViewDidScroll:
代理里去设置显示的图片,ScrollView
各种不按常理去偏移,最后在scrollViewDidEndDecelerating:
代理方法去实现图片的显示和偏移量。
定时器效果:
定时器看起来,没毛病,可是等拖拽的时候就懵逼了,因为一滑的快的话就有问题了。当滑到最后一张的时候因为代理方法的调用时间,所以有可能来不及设置回到第一张图片。
后面由于种种原因就又回到了UICollectionView
,在这里用的就是第二种方法完全自定义分页的宽度。
- (void)snapToPage { CGPoint pageOffset; pageOffset.x = [self pageOffsetForComponent:YES]; pageOffset.y = [self pageOffsetForComponent:NO]; CGPoint currentOffset = self.contentOffset; if (!CGPointEqualToPoint(pageOffset, currentOffset)) { _snapping = YES; [self setContentOffset:pageOffset animated:YES]; } _dragVelocity = CGPointZero; _dragDisplacement = CGPointZero; }
- (CGFloat)pageOffsetForComponent:(BOOL)isX { if (((isX ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds)) == 0) || ((isX ? self.contentSize.width : self.contentSize.height) == 0)) return 0; CGFloat pageLength = isX ? _pageWidth : _pageHeight; if (pageLength < FLT_EPSILON) pageLength = isX ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds); pageLength *= self.zoomScale; CGFloat totalLength = isX ? self.contentSize.width : self.contentSize.height; CGFloat visibleLength = (isX ? CGRectGetWidth(self.bounds) : CGRectGetHeight(self.bounds)) * self.zoomScale; CGFloat currentOffset = isX ? self.contentOffset.x : self.contentOffset.y; CGFloat dragVelocity = isX ? _dragVelocity.x : _dragVelocity.y; CGFloat dragDisplacement = isX ? _dragDisplacement.x : _dragDisplacement.y; CGFloat newOffset; CGFloat index = currentOffset / pageLength; CGFloat lowerIndex = floorf(index); CGFloat upperIndex = ceilf(index); if (ABS(dragDisplacement) < DRAG_DISPLACEMENT_THRESHOLD || dragDisplacement * dragVelocity < 0) { if (index - lowerIndex > upperIndex - index) { index = upperIndex; } else { index = lowerIndex; } } else { if (dragVelocity > 0) { index = upperIndex; } else { index = lowerIndex; } } newOffset = pageLength * index; if (newOffset > totalLength - visibleLength) newOffset = totalLength - visibleLength; if (newOffset < 0) newOffset = 0; return newOffset; }
#pragma mark - ScrollView delegate- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { _dragDisplacement = scrollView.contentOffset; if (_delegateRespondsToWillBeginDragging) [_actualDelegate scrollViewWillBeginDragging:scrollView]; } - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { if (_pagingEnabled) { *targetContentOffset = scrollView.contentOffset; _dragVelocity = velocity; _dragDisplacement = CGPointMake(scrollView.contentOffset.x - _dragDisplacement.x, scrollView.contentOffset.y - _dragDisplacement.y); } else { if (_delegateRespondsToWillEndDragging) [_actualDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; } } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate && _pagingEnabled) [self snapToPage]; if (_delegateRespondsToDidEndDragging) [_actualDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (_pagingEnabled) [self snapToPage]; if (_delegateRespondsToDidEndDecelerating) [_actualDelegate scrollViewDidEndDecelerating:scrollView]; } - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { if (!_snapping && _pagingEnabled) { [self snapToPage]; } else { _snapping = NO; } if (_delegateRespondsToDidEndScrollingAnimation) [_actualDelegate scrollViewDidEndScrollingAnimation:scrollView]; } - (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { if (_pagingEnabled) [self snapToPage]; if (_delegateRespondsToDidEndZooming) [_actualDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale]; }
以上的代码都是在 网上 查找到的,最后实现了想要的效果。由于这里我用的是UICollcetionView
,所以就直接自定义了一个GPCollectionView
继承于UICollectionView
,最后却发现UICollectionViewDelegate
的方法始终不会调用,UIScrollViewDelegate
的方法却能调用,在此希望大神们能解释一下。
最后附上代码
利用 ScrollView 实现分页效果
利用 UICollectionView 实现分页效果
作者:藍眼淚
链接:https://www.jianshu.com/p/2604ceb1b5d5
共同学习,写下你的评论
评论加载中...
作者其他优质文章