美文网首页学无止境上海恩美路演OC开发
iOS 类似腾讯视频轮播器+缩放效果

iOS 类似腾讯视频轮播器+缩放效果

作者: CoderGuogt | 来源:发表于2017-03-05 16:28 被阅读1526次

    在最近公司项目需求,要求实现类似于腾讯视频轮播器的效果,另外需要加上缩放效果,先上实现的效果图

    定时器效果


    手动拖拽效果



    手动拖拽的时候可以看到随着拖动的操作,图片有个放大的效果,以上就是所要实现的最终效果。

    可能看到这里,你会想到 UICollectionView,自定义布局,每次滑动结束的时候,将距离屏幕中心位置最近的Item 显示在中间,然后将显示在屏幕中的 Item 进行设置 transform属性。
    在一开始看到这个需求的时候,也没有考虑到这么多,认为一个UICollectionView就能搞定这个需求。可是当自己把自定义布局实现了,然后鼠标随手一拽,速度一块,发现有多个 Item 已经随着滚动过去了,这明显不能满足需求,如果将pageEnable 属性设置为 YES,虽然可以不让多个 Item 滚动过去,但是UICollectionViewcontentOffset又不正确,默认的分页宽度为UICollectionView的宽度。于是在网上找到方案:第一种是将 UIScrollView的宽度设置为我们想要的每页的偏移宽度,然后将UIScrollViewclipsToBounds设置为 NO,这样每次滑动就能达到我们想要的偏移量。第二种是完全自定义分页宽度。
    先说说第一种方法:
    在将UICollectionViewframe设置为想要的偏移量大小时,因为复用机制,每次滑出 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 实现分页效果

    相关文章

      网友评论

      • DarrenG:功能实现给你点个赞 ! 作者可以把整个过程梳理一下 从新发表一篇文章么
        CoderGuogt:@DarrenG 行,那我看下放假的时候整理一下
        DarrenG:@藍眼淚 我是初级有些代码上的的使用有点看不懂 比如说从写父类的PagedingEndable的set 方法时用了一个@synthesize 我查了一上午 :joy: 想好好学习实现代码以及设计思路 希望君愿意腾出时间共同分享:+1:
        CoderGuogt:@DarrenG 谢谢支持,这个有空我再重新整理一下吧,当时写的时候时间比较赶
      • 西蒙SIMON:兄弟,你这个不是Demo,是笔试题啊,set个delegate写得这么麻烦。UICollectionView和UIScrollView都有delegate属性,但是UICollectionView的delegate的settter、getter方法被重写了。系统的getter和setter应该是做了其他逻辑判断什么的,由于scrollView的setter、getter没有重写,能正常运行。而collectionView的却被改写了,导致不能响应。
        CoderGuogt:我那个自定义的 CollectionView 的代码都是网上找的,只是为了实现自定义分页,后面也试着把代理抽出到 BannerView 中,但是点左右两边的 Item 会让 CollectionView 偏移

      本文标题:iOS 类似腾讯视频轮播器+缩放效果

      本文链接:https://www.haomeiwen.com/subject/lhfegttx.html