为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
iOS

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

定时器效果


手动拖拽效果



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

可能看到这里,你会想到 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 实现分页效果



作者:藍眼淚
链接:https://www.jianshu.com/p/2604ceb1b5d5


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消