在很多的项目中,都会用到图片轮播这个功能,如今网上关于图片轮播的轮子也层出不穷,千奇百怪,笔者根据本身的思路,用两个imageView也实现了图片轮播,这里给你们介绍笔者的主要思路以及大概步骤。git
最底层是一个UIView,上面有一个UIScrollView和UIPageControl,scrollView上有两个UIImageView,imageView的宽高=scrollView的宽高=view的宽高github
假设轮播控件的宽为x,高为y,咱们设置scrollView的contentSize的宽度为3x,而且让scrollView在x方向偏移量为x,即显示中间内容web
scrollView.contentSize = CGSizeMake(3x, y); scrollView.contentOffset = CGPointMake(x, 0);
接下来使用代理方法scrollViewDidScroll来监听scrollView的滚动,定义一个枚举来记录滚动的方向数组
typedef NS_ENUM(NSInteger, Direction) { DirectionNone = 1 << 0, DirectionLeft = 1 << 1, DirectionRight = 1 << 2 }; // 滚动方向 @property (nonatomic, assign) Direction direction; - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat offX = scrollView.contentOffset.x; self.direction = offX > self.width ? DirectionLeft : offX < self.width ? DirectionRight : DirectionNone; }
重写direction的setter方法,根据滚动方向来设置下一张图片的显示,若是是往左边滚动,那么下一张图片的位置应该在右边,若是是往右滚动,那么下一张图片的位置应该在左边。(ps:此处应该注意滚动到第一张和最后一张的边界状况)缓存
#pragma mark - 设置滚动方向 - (void)setDirection:(Direction)direction { if (_direction == direction) return; _direction = direction; if (_direction == DirectionNone) return; if (_direction == DirectionRight) { // 若是是向右滚动 self.nextImageView.frame = CGRectMake(0, 0, self.width, self.height); self.nextIndex = self.currentIndex - 1; if (self.nextIndex < 0) self.nextIndex = _images.count - 1; }else if (_direction == DirectionLeft){ // 若是是向左边滚动 self.nextImageView.frame = CGRectMake(CGRectGetMaxX(_currentImageView.frame), 0, self.width, self.height); self.nextIndex = (self.currentIndex + 1) % _images.count; } self.nextImageView.image = self.images[self.nextIndex]; }
经过代理方法scrollViewDidEndDecelerating来监听滚动结束,结束后,会变成如下两种状况:服务器
此时,scrollView的偏移量为0或者2x两种状况,咱们经过代码再次将scrollView的偏移量设置为x,而且将nextImageView的图片修改成赋值给currentImageView的图片网络
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self pauseScroll]; } - (void)pauseScroll { // 等于1表示没有滚动 if (self.scrollView.contentOffset.x / self.width == 1) return; self.currentIndex = self.nextIndex; self.pageControl.currentPage = self.currentIndex; self.currentImageView.frame = CGRectMake(self.width, 0, self.width, self.height); self.descLabel.text = self.describeArray[self.currentIndex]; self.currentImageView.image = self.nextImageView.image; self.scrollView.contentOffset = CGPointMake(self.width, 0); }
这样以后,咱们看到的仍是currentImageView,只是图片显示的是下一张的图片或者上一张的图片,又回到了最初的样子。异步
轮播的功能实现了,接下来就是添加定时器让它自动滚动了。oop
// 开启定时器 - (void)startTimer { // 若是只有一张,直接放回,不须要开启定时器 if (_images.count <= 1) return; // 若是定时器已经开启,则先中止再开启 if (self.timer) [self stopTimer]; self.timer = [NSTimer timerWithTimeInterval:_time < 1 ? DEFAULTTIME : _time target:self selector:@selector(nextPage) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; } // 下一页 - (void)nextPage { [self.scrollView setContentOffset:CGPointMake(self.width * 2, 0) animated:YES]; }
setContentOffset:animated:方法执行完毕后不会调用scrollview的scrollViewDidEndDecelerating方法,可是会调用scrollViewDidEndScrollingAnimation方法,所以咱们要在该方法中调用pauseScrollatom
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [self pauseScroll]; }
当咱们手动拖拽的时候,须要中止自动滚动,此时咱们只须要关闭定时器就好了,当咱们拖拽结束的时候,从新启动定时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self stopTimer]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { [self startTimer]; }
在实际开发中,咱们不多自动轮播本地的图片,大部分都是服务器获取的图片url,也有可能既有本地图片,又有网络图片,那么该如何加载呢?
下载图片,先从缓存中取,若是有,则替换以前的占位图片,若是没有,去沙盒中取,若是有,替换占位图片,并添加到缓存中,若是没有,开启异步线程下载
在实际开发中,一般轮播图都有点击图片跳转到对应的内容的操做,所以须要监听图片的点击,提供两种思路:
经过block:
- 定义一个block给外界
- 打开currentImageView的用户交互
- 给currentImageView添加一个点击手势
- 在点击手势响应方法里面调用block,并传入图片所在的索引
经过代理:
- 定义一个协议方法,设置一个代理属性
- 打开currentImageView的用户交互
- 给currentImageView添加一个点击手势
- 在点击手势响应方法里面用代理调用协议方法,
上面是笔者实现轮播图的思路以及部分代码,须要源码的请戳这里,若是在使用中发现有bug,欢迎提出!若是以为好用,记得献上你的star哦!