你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
iOS 两种不同的图片无限轮播
立即下载
用AI写一个
该例子支持:好用才打赏哦
现在下载学习
发布时间:2017-09-07
78人
|
浏览:7786次
|
收藏
|
分享
技术:ios
运行环境:ios8+
概述
到目前为止,我见过的轮播方法,大概有那么三种,由于轮播嘛,所以肯定都是在UIScrollView的基础上
详细
######前记 其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:`时间就像海绵,挤一挤还是有的`。记得在刚刚开始工作的时候,第一个接触到比较酷的东西就是图片的无限轮播,那还是三年多前的一个火辣辣的夏天,其实可以说是秋天,然而天府之国的成都并没有....下面我们进入正题吧 ######轮播的方式 到目前为止,我见过的轮播方法,大概有那么三种,由于轮播嘛,所以肯定都是在`UIScrollView`的基础上 **1**、在`UIScrollView`上添加`N+2`个`UIImageView` **2**、在`UIScrollView`上添加固定的`3`个`UIImageView` **3**、利用重用机制中的`UICollectionView`来实现 ######原理 下面,就简单阐述下三种不同方法的原理,以及其优缺点 - 第一种:其原理图大概如下 ![N+1.png](/contentImages/image/jianshu/2525768-4fb0788bf26d72bf.png) 该方案的原理是在`UIScrollView `上添加`N+2`个`UIImageView `,比如上图中,有三张需要轮播的图,那么我们可以添加五个`UIImageView`在`UIScrollView`上,图片赋值的顺序如上图,当我们向左滑动到最左的时候,即到`3`这个位置的时候,调用`setContentOffset `,让其滚动到右边的`3`这个位置,当然不能调用动画,这样肉眼是看不出来的,给我们造成一种视角错觉,如果是向右滑动到最右边的`1`,其原理也是一样的。 优点:容易理解 缺点:如果有`100`个图片,那么我们岂不是要添加`102`个,这样的话,内存肯定是吃不消的把。 - 第二种:其原理图大概如下 ![3.png](/contentImages/image/jianshu/2525768-668574b0350d33aa.png) 该方案的原理是在`UIScrollView `上添加固定的`3`个`UIImageView `,在初始化的时候,分别如上图那样赋值,并且调用`setContentOffset`,让其居中。of course,这只是前奏,对比第一种方法,肯定在逻辑处理上复杂点。 复杂逻辑,当我们向左或者向右滑动一张图片后,需要根据当前滚动的`index`来设置图片,并且由于滑动后`UIScrollView`的`contentOffset`发生了改变,后续还需要处理一些其他逻辑。 比如向左滑动的话,就到了最右边,这样,我们再向右就不能再滑动了,所以为了保证能继续滑动,我们需要在滑动结束的时候,设置`contentOffset`,使第二个`UIImageView`一直处于屏幕中间,除此之外,我们还需要重新设置图片,由于我们向左滑动,图中的`2`显示的图片其实是我们需要展示的,因为我们要设置`contentOffset`,这样`2`这个`imageView`就又移动到最右边去了,所以这时候我们设置图片,就要将`1`的`imageView`设置为后面一张即`2`的`imageView`的图片,将`3`的`imageView`设置为`1`之前的图片,如此来实现循环。 下面是部分代码 ``` //减速停止的时候 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { _endOffsetX = scrollView.contentOffset.x; //给imageview赋值 [self loadImage]; //改变offset [_scrollView setContentOffset:CGPointMake(self.bounds.size.width, 0) animated:NO]; if (self.didScrollToIndexBlock) { self.didScrollToIndexBlock(_currentIndex); } } ``` 效果如如下: ![轮播1.gif](/contentImages/image/jianshu/2525768-b9ff195af799ef22.gif) 优点:相比第一种,内存上开销很小 缺点:代码稍多,理解复杂,如果非常快速滑动,可能会出现最右或者最左滑不动,因为`scrollViewDidEndDecelerating`还未执行 - 第三种:其原理图大概如下 ![collectionview.png](/contentImages/image/jianshu/2525768-b3d4c1317bd187d5.png) 其原理很简单,主要是根据`UICollectionView `的重用机制,通过创建许多个`cell`,然后来实现,当然,内存就不用去考虑了,因为这个是通过重用机制实现的。 下面是部分代码 ***创建UICollectionView*** ``` - (void)addCollectionView { self.collectionFlowLayout = [[UICollectionViewFlowLayout alloc] init]; self.collectionFlowLayout.minimumLineSpacing = 0; self.collectionFlowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal; self.collectionFlowLayout.itemSize = self.bounds.size; self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:self.collectionFlowLayout]; self.collectionView.dataSource = (id)self; self.collectionView.delegate = (id)self; self.collectionView.pagingEnabled = YES; self.collectionView.showsVerticalScrollIndicator = self.collectionView.showsHorizontalScrollIndicator = NO; [self.collectionView registerClass:[GLRollingScrollviewCell class] forCellWithReuseIdentifier:GLRollingScrollviewCellId]; [self addSubview:self.collectionView]; } ``` ***自动滚动定时器部分*** ``` //开启定时器 - (void)startTimer { [self cofigTimer]; } //关闭定时器 - (void)pauseTimer { if (self.timer) { CFRunLoopTimerInvalidate(self.timer); CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), self.timer, kCFRunLoopCommonModes); } } //配置定时器 - (void)cofigTimer { if (self.imageUrlArray.count <= 1) { return; } if (self.timer) { CFRunLoopTimerInvalidate(self.timer); CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), self.timer, kCFRunLoopCommonModes); } __weak typeof(self)weakSelf = self; CFRunLoopTimerRef time = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()+ _intervalTimer, _intervalTimer, 0, 0, ^(CFRunLoopTimerRef timer) { [weakSelf autoScroll]; }); self.timer = time; CFRunLoopAddTimer(CFRunLoopGetCurrent(), time, kCFRunLoopCommonModes); } //自动滚动 - (void)autoScroll { NSInteger currentIndex = (self.collectionView.contentOffset.x + self.collectionFlowLayout.itemSize.width * 0.5) / self.collectionFlowLayout.itemSize.width; NSInteger toIndex = currentIndex + 1; NSIndexPath *indexPath = nil; if (toIndex == self.totalNumber) { toIndex = self.totalNumber * 0.5; indexPath = [NSIndexPath indexPathForRow:toIndex inSection:0]; [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:NO]; } else { indexPath = [NSIndexPath indexPathForItem:toIndex inSection:0]; [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES]; } } ``` ***手动滑动时避免和定时器冲突*** ``` - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self pauseTimer]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { [self startTimer]; } ``` ***计算当前index*** ``` - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (self.totalNumber == 0) { return; } NSInteger currentIndex = (scrollView.contentOffset.x + self.collectionView.frame.size.width * 0.5) / self.collectionView.frame.size.width;; currentIndex = currentIndex % self.imageUrlArray.count; CGFloat x = scrollView.contentOffset.x - self.collectionView.frame.size.width; NSUInteger index = fabs(x) / self.collectionView.frame.size.width; CGFloat fIndex = fabs(x) / self.collectionView.frame.size.width; //下面的第二个条件 可以确保 尽量一次去执行block 而不多次 if (self.rollingDidScrollBlock && fabs(fIndex - (CGFloat)index) <= 0.00001) { // NSLog(@" 打印信息:%ld",(long)currentIndex); self.rollingDidScrollBlock(currentIndex); } } ``` 在上面代理`scrollViewDidScroll `中,有个关键地方,大家都知道`scrollViewDidScroll `只要再滑动过程中就会一直执行,为了避免多次执行,而导致内存问题,我们希望的是尽可能的在滑动结束的时候来执行,所以这个地方,加了一句判断`fabs(fIndex - (CGFloat)index) <= 0.00001`,因为在结束的时候,这两个值的差应该很小,几乎可以为0。所以,这样就不会导致代码在此多次执行。 ######项目文件截图: ![](/contentImages/image/20170907/W6W5maW2DrEWUcjeyCN.jpg) ######文章结尾 针对上的三种方法,我对后面两种方式写了两个简单的`demo`,希望对大家有帮助。
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
敷衍丶尘世
16
例子数量
615
帮助
43
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
iOS 仿支付宝密码支付
iOS 九宫格手势密码
iOS CAReplicatorLayer 简单动画
iOS 之UIBezierPath
iOS 核心动画 Core Animation浅谈
iOS CoreImage之滤镜简单使用
iOS UIButton文字和图片间距随意调整
iOS 简单引导界面
iOS 两种不同的图片无限轮播
iOSQuart2D绘图之UIImage简单使用
iOS 自定义键盘
iOS 自定义转场动画浅谈
iOS Core ML与Vision初识
iOS 11之Vision人脸检测
iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)
iOS 音频视频图像合成那点事