代码地址如下:
http://www.demodashi.com/demo/11608.html

前记

其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:时间就像海绵,挤一挤还是有的。记得在刚刚开始工作的时候,第一个接触到比较酷的东西就是图片的无限轮播,那还是三年多前的一个火辣辣的夏天,其实可以说是秋天,然而天府之国的成都并没有….下面我们进入正题吧

轮播的方式

到目前为止,我见过的轮播方法,大概有那么三种,由于轮播嘛,所以肯定都是在UIScrollView的基础上

1、在UIScrollView上添加N+2UIImageView
2、在UIScrollView上添加固定的3UIImageView
3、利用重用机制中的UICollectionView来实现

原理

下面,就简单阐述下三种不同方法的原理,以及其优缺点

  • 第一种:其原理图大概如下

该方案的原理是在UIScrollView上添加N+2UIImageView,比如上图中,有三张需要轮播的图,那么我们可以添加五个UIImageViewUIScrollView上,图片赋值的顺序如上图,当我们向左滑动到最左的时候,即到3这个位置的时候,调用setContentOffset,让其滚动到右边的3这个位置,当然不能调用动画,这样肉眼是看不出来的,给我们造成一种视角错觉,如果是向右滑动到最右边的1,其原理也是一样的。

优点:容易理解
缺点:如果有100个图片,那么我们岂不是要添加102个,这样的话,内存肯定是吃不消的把。
- 第二种:其原理图大概如下

该方案的原理是在UIScrollView上添加固定的3UIImageView,在初始化的时候,分别如上图那样赋值,并且调用setContentOffset,让其居中。of course,这只是前奏,对比第一种方法,肯定在逻辑处理上复杂点。
复杂逻辑,当我们向左或者向右滑动一张图片后,需要根据当前滚动的index来设置图片,并且由于滑动后UIScrollViewcontentOffset发生了改变,后续还需要处理一些其他逻辑。
比如向左滑动的话,就到了最右边,这样,我们再向右就不能再滑动了,所以为了保证能继续滑动,我们需要在滑动结束的时候,设置contentOffset,使第二个UIImageView一直处于屏幕中间,除此之外,我们还需要重新设置图片,由于我们向左滑动,图中的2显示的图片其实是我们需要展示的,因为我们要设置contentOffset,这样2这个imageView就又移动到最右边去了,所以这时候我们设置图片,就要将1imageView设置为后面一张即2imageView的图片,将3imageView设置为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);}
}

效果如如下:

优点:相比第一种,内存上开销很小
缺点:代码稍多,理解复杂,如果非常快速滑动,可能会出现最右或者最左滑不动,因为scrollViewDidEndDecelerating还未执行

  • 第三种:其原理图大概如下


其原理很简单,主要是根据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:indexPathatScrollPosition:UICollectionViewScrollPositionNoneanimated: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。所以,这样就不会导致代码在此多次执行。

项目文件截图:

文章结尾

针对上的三种方法,我对后面两种方式写了两个简单的demo,希望对大家有帮助。iOS 两种不同的图片无限轮播

代码地址如下:
http://www.demodashi.com/demo/11608.html

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

iOS 两种不同的图片无限轮播相关推荐

  1. iOS开发之ImageView复用实现图片无限轮播

    在上篇博客中iOS开发之多图片无缝滚动组件封装与使用给出了图片无限轮播的实现方案之一,下面在给出另一种解决方案.今天博客中要说的就是在ScrollView上贴两个ImageView, 把ImageVi ...

  2. iOS换一种思路写一个无限轮播的滚动视图

    换一种思路写一个无限轮播的滚动视图 写这篇博客已经距离我当时写差不多有一个月时间了,也完善了很多,基本是没有bug的,如果有,不妨留言,喜欢的话,劳烦各位点个赞,不喜欢的,不妨看看思路,提提意见 1. ...

  3. iOS 自定义图片无限轮播控件

    一:简介 图片轮播功能在App中是一个非常常见的功能,即允许定时滚动,也允许拖拽滚动,也可以点击每张图片触发事件. 二:实现方式 图片轮播功能的实现方式有很多中, UIScrollView + N个U ...

  4. BannerLayoutSimple 支持图片无限轮播的 BannerLayout,支持自定义小圆点位置以及显示位置等等,反正支持的挺多的,源码也有注释

    BannerLayoutSimple 项目地址: 7449/BannerLayoutSimple 简介:支持图片无限轮播的 BannerLayout,支持自定义小圆点位置以及显示位置等等,反正支持的挺 ...

  5. Android实现广告页图片无限轮播

    一.概述 对于一个联网的Android应用, 首页广告无限轮播基本已经成为标配了. 那么它是怎么实现的呢? 有几种实现方式呢? 二.无限轮播的实现 1.最常规的手段是用 ViewPager来实现 2. ...

  6. 安卓实现广告栏图片无限轮播播放效果

    //经常在安卓app中页面上方放置一个广告栏,用到的无限轮播代码: public class MainActivity extends Activity { // 广告控件 private MyPag ...

  7. iOS两种设置启动图片的方式

    设置启动界面有两种方式,都在工程配置界面中,如图: 推荐用Launch Screen File方式,优点是只需要在storyboard中设置一张图片就可以,而且还可以加各种控件排版,比较灵活. Lau ...

  8. vue 实现无限轮播_vue图片无限轮播

    近期项目中出现了很多图片轮播的需求,趁此机会写了一个关于图片自动轮播,手动切换的小Demo,具体效果看下图: 屏幕快照 2018-10-25 上午9.47.30.png 具体实现代码如下: v-sho ...

  9. iOS无限轮播图片的两种方式

    2019独角兽企业重金招聘Python工程师标准>>> 1 使用UIScrollview实现无限轮播原理 在开发中常需要对广告或者是一些图片进行自动的轮播,也就是所谓的无限滚动. 在 ...

最新文章

  1. 数学各个研究方向简介
  2. OCRNet: 目标区域上下文信息的特征表达 | ECCV 2020
  3. [luogu2576 SCOI2010] 幸运数字 (容斥原理)
  4. 开源库OpenNMT-py使用记录
  5. 2020 中国技术力量年度榜单
  6. radiobutton怎么变成竖排_衣服如此凌乱?怎么能忍受的了?衣柜收纳,试试这些神器吧...
  7. mybatis学习(17):列名与属性名不一致的情况(使用别名)
  8. A5D2 GPIO测试
  9. 5种不会被机器智能替代的能力
  10. java中的让步_java基本教程之线程让步 java多线程教程
  11. Android Q 不叫 Q,正式命名为 Android 10
  12. 黑马MFC教程总结(后续更新)
  13. 苹果电脑如何设置屏保时间?
  14. 3串锂电池充电保护板设计
  15. sublime好看的字体设置
  16. 计算机二级12月报名时间广东,18年广东省全国计算机等级考试报名:12月15日起...
  17. github上的html项目怎么运行,GitHub搭建简单的项目“Hello HTML”
  18. leetcode 1103分糖果II
  19. _.chunk的用法
  20. android会超过苹果,任正非:超过苹果和安卓的华为操作系统,不会超过三百年...

热门文章

  1. 利用PCF8591进行AD转换
  2. linux多线程学习(七)——实现“生产者和消费者”
  3. linux路由内核实现分析(二)---FIB相关数据结构(4)
  4. C语言中全局变量和局部变量,作用域与生命周期的相关问题。
  5. 把数字随机分成 php,php随机数 微信随机生成红包金额算法php版
  6. 《深入理解 Spring Cloud 与微服务构建》第十七章 使用 Spring Cloud OAuth2 保护微服务系统
  7. 【重难点】【JUC 02】volitale 常用模式 、JUC 下有哪些内容 、并发工具类
  8. spring-boot-maven-plugin插件
  9. Web前端-Vue.js必备框架(一)
  10. 从Git的下载到使用github详细教程