前言

在不少的项目中,都会用到图片轮播这个功能,现在网上关于图片轮播的轮子也层出不穷,千奇百怪,笔者根据自己的思路,用两个imageView也实现了图片轮播,这里给大家介绍笔者的主要思路以及大概步骤。

轮播实现步骤

层级结构

最底层是一个UIView,上面有一个UIScrollView和UIPageControl,scrollView上有两个UIImageView,imageView的宽高=scrollView的宽高=view的宽高

轮播原理

假设轮播控件的宽为x,高为y,我们设置scrollView的contentSize的宽度为3x,并且让scrollView在x方向偏移量为x,即显示中间内容

  1. scrollView.contentSize = CGSizeMake(3x, y);
  2. scrollView.contentOffset = CGPointMake(x, 0);

接下来使用代理方法scrollViewDidScroll来监听scrollView的滚动,定义一个枚举来记录滚动的方向

  1. typedef NS_ENUM(NSInteger, Direction) {
  2. DirectionNone = 1 << 0,
  3. DirectionLeft = 1 << 1,
  4. DirectionRight = 1 << 2
  5. };
  6. // 滚动方向
  7. @property (nonatomic, assign) Direction direction;
  8. - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  9. CGFloat offX = scrollView.contentOffset.x;
  10. self.direction = offX > self.width ? DirectionLeft : offX < self.width ? DirectionRight : DirectionNone;
  11. }

重写direction的setter方法,根据滚动方向来设置下一张图片的显示,如果是往左边滚动,那么下一张图片的位置应该在右边,如果是往右滚动,那么下一张图片的位置应该在左边。(ps:此处应该注意滚动到第一张和最后一张的边界情况)

  1. #pragma mark - 设置滚动方向
  2. - (void)setDirection:(Direction)direction {
  3. if (_direction == direction) return;
  4. _direction = direction;
  5. if (_direction == DirectionNone) return;
  6. if (_direction == DirectionRight) { // 如果是向右滚动
  7. self.nextImageView.frame = CGRectMake(0, 0, self.width, self.height);
  8. self.nextIndex = self.currentIndex - 1;
  9. if (self.nextIndex < 0) self.nextIndex = _images.count - 1;
  10. }else if (_direction == DirectionLeft){ // 如果是向左边滚动
  11. self.nextImageView.frame = CGRectMake(CGRectGetMaxX(_currentImageView.frame), 0, self.width, self.height);
  12. self.nextIndex = (self.currentIndex + 1) % _images.count;
  13. }
  14. self.nextImageView.image = self.images[self.nextIndex];
  15. }

通过代理方法scrollViewDidEndDecelerating来监听滚动结束,结束后,会变成以下两种情况:

  • 左滚之后

  • 右滚之后

此时,scrollView的偏移量为0或者2x两种情况,我们通过代码再次将scrollView的偏移量设置为x,并且将nextImageView的图片修改为赋值给currentImageView的图片

  1. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
  2. [self pauseScroll];
  3. }
  4. - (void)pauseScroll {
  5. // 等于1表示没有滚动
  6. if (self.scrollView.contentOffset.x / self.width == 1) return;
  7. self.currentIndex = self.nextIndex;
  8. self.pageControl.currentPage = self.currentIndex;
  9. self.currentImageView.frame = CGRectMake(self.width, 0, self.width, self.height);
  10. self.descLabel.text = self.describeArray[self.currentIndex];
  11. self.currentImageView.image = self.nextImageView.image;
  12. self.scrollView.contentOffset = CGPointMake(self.width, 0);
  13. }

这样之后,我们看到的还是currentImageView,只是图片显示的是下一张的图片或者上一张的图片,又回到了最初的样子。

自动滚动

轮播的功能实现了,接下来就是添加定时器让它自动滚动了。

  1. // 开启定时器
  2. - (void)startTimer {
  3. // 如果只有一张,直接放回,不需要开启定时器
  4. if (_images.count <= 1) return;
  5. // 如果定时器已经开启,则先停止再开启
  6. if (self.timer) [self stopTimer];
  7. self.timer = [NSTimer timerWithTimeInterval:_time < 1 ? DEFAULTTIME : _time target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
  8. [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
  9. }
  10. // 下一页
  11. - (void)nextPage {
  12. [self.scrollView setContentOffset:CGPointMake(self.width * 2, 0) animated:YES];
  13. }

注意

setContentOffset:animated:方法执行完毕后不会调用scrollview的scrollViewDidEndDecelerating方法,但是会调用scrollViewDidEndScrollingAnimation方法,因此我们要在该方法中调用pauseScroll

  1. - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
  2. [self pauseScroll];
  3. }

拖拽时停止定时器

当我们手动拖拽的时候,需要停止自动滚动,此时我们只需要关闭定时器就行了,当我们拖拽结束的时候,重新启动定时器

  1. - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
  2. [self stopTimer];
  3. }
  4. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
  5. [self startTimer];
  6. }

加载图片

在实际开发中,我们很少自动轮播本地的图片,大部分都是服务器获取的图片url,也有可能既有本地图片,又有网络图片,那么该如何加载呢?

  1. 定义一个imageArr用来接收外界传进来的数组(可以是图片,也可以是网络图片路径,可以图片和路径混合)
  2. 定义一个images用来存储图片(只装图片).判断外界传进来的数组,如果是图片,直接添加到images,如果是连接,先添加一张默认的占位图
  3. 定义一个imageDic用来缓存图片的字典,key为图片URL
  4. 定义一个operationDic用来保存下载操作的字典,key为图片URL

图片缓存策略(SDWebImage的思路)

下载图片,先从缓存中取,如果有,则替换之前的占位图片,如果没有,去沙盒中取,如果有,替换占位图片,并添加到缓存中,如果没有,开启异步线程下载

监听图片点击

在实际开发中,通常轮播图都有点击图片跳转到对应的内容的操作,因此需要监听图片的点击,提供两种思路:

  • 通过block:

    1. 定义一个block给外界
    2. 打开currentImageView的用户交互
    3. 给currentImageView添加一个点击手势
    4. 在点击手势响应方法里面调用block,并传入图片所在的索引
  • 通过代理:

    1. 定义一个协议方法,设置一个代理属性
    2. 打开currentImageView的用户交互
    3. 给currentImageView添加一个点击手势
    4. 在点击手势响应方法里面用代理调用协议方法,

结束语

上面是笔者实现轮播图的思路以及部分代码,需要源码的请戳这里,如果在使用中发现有bug,欢迎提出!如果觉得好用,记得献上你的star哦!

两个imageView实现图片轮播的更多相关文章

  1. 高效图片轮播,两个imageView实现

    本文是投稿文章,作者:codingZero 导语 在不少项目中,都会有图片轮播这个功能,现在网上关于图片轮播的框架层出不穷,千奇百怪,笔者根据自己的思路,用两个imageView也实现了图片轮播,这里 ...

  2. 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结

    史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...

  3. iOS之两个ImageView实现图片滚动

    原创作者:codingZero 导语 在不少项目中,都会有图片轮播这个功能,现在网上关于图片轮播的框架层出不穷,千奇百怪,笔者根据自己的思路,用两个imageView也实现了图片轮播,这里说说笔者的主 ...

  4. UIScrollView实现图片轮播器及其无限循环效果

    图片轮播器: 一.实现效果 实现图片的自动轮播            二.实现代码 storyboard中布局 代码: 1 #import "YYViewController.h" ...

  5. iOS开发UI篇—UIScrollView控件实现图片轮播

    iOS开发UI篇—UIScrollView控件实现图片轮播 一.实现效果 实现图片的自动轮播            二.实现代码 storyboard中布局 代码: #import "YYV ...

  6. Android学习笔记之图片轮播...

    PS:一个bug又折腾了一个下午....哎... 学习内容: 1.Android利用ViewPager和PagerAdapter实现图片轮播... 2.使用反射机制获取Android的资源信息... ...

  7. IOS第六天(3:scrollView 图片轮播器)

    IOS第六天(3:scrollView 图片轮播器) #import "HMViewController.h" #define kImageCount 5 @interface H ...

  8. Swift 使用CollectionView 实现图片轮播封装就是这样简单

    前言: 这篇你可以学会自定义视图,创建collectionView,协议的使用,定时器; 自制图片 先上Demo:Github上封装好的下载即用, 好用请Star Thanks首先新建一个继承于UIV ...

  9. Android高级图片滚动控件,编写3D版的图片轮播器

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17482089 大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博 ...

随机推荐

  1. leetcode 214. 最短回文串 解题报告

    给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串.找到并返回可以用这种方式转换的最短回文串. 示例 1: 输入: "aacecaaa" 输出: "aaa ...

  2. php数组循环的三种方式

    PHP 的遍历数组的三种方式:for循环.foreach循环.while.list().each()组合循环 PHP当中数组分为:索引数组[转换成json是数组]和关联数组[转换成json是对象] f ...

  3. VB.NET视频总结——后续篇

    上篇基础总结简单介绍了前几个单元的主要内容和理解的思路,这篇介绍后几个单元的内容,主要介绍了应用程式的设计与部署方面的内容. 首先,第十一单元讲的是应用程式设计的基础,主要讲解了元件的相关知识.应用程 ...

  4. sql优化(转)

    explain +sql分析sql语句执行效率 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用! ...

  5. [NC2018-9-9T1]中位数

    题目大意:给你一个长度为$n$的序列,要求出长度大于等于$len$的字段的中位数中最大的一个中位数 题解:可以二分答案,对于比它小的数赋成$-1$,大的赋成$1$.求前缀和,若有一段区间的和大于$0$ ...

  6. 项链 [FFT]

    题面 思路 这题很像bzoj4827礼物 还是一样的思路,我们把$y$倍长,$y[i+k]=y[i]+n$ 然后令$f(s,c)$表示从$y$的第$s$个开始匹配,位置偏移量为$c$的答案 可以得到$ ...

  7. POJ A Simple Problem with Integers | 线段树基础练习

    #include<cstdio> #include<algorithm> #include<cstring> typedef long long ll; #defi ...

  8. BZOJ1951 [Sdoi2010]古代猪文 【费马小定理 + Lucas定理 + 中国剩余定理 + 逆元递推 + 扩展欧几里得】

    题目 "在那山的那边海的那边有一群小肥猪.他们活泼又聪明,他们调皮又灵敏.他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心--" --选自猪王国民歌 很久很久以前,在山的那 ...

  9. [解决方案]Senparc.CO2NET 初始编译报错的问题

    Senparc.CO2NET.Sample.net45 如果点击重新生成,报一下错误,那么解决办法如下: 解决方案: 1.Windows + R 打开运行,输入Regedit 2.找到项目录HKEY_ ...

  10. ZJUTACM

    描述 这回是浙江工业大学的ACM程序设计竞赛,欢迎你的到来!但是,请稍等!裁判Joe说了,必须正确回答他的问题,才可以看到PIPI的气球MM,KUKU的气球GG.Joe手上有7张卡片,每张卡片上有一个 ...