三张 imageView实现轮播图无限轮播
github地址:https://github.com/leshengping/SPCarouselScrollView
#import "SPCarouselScrollView.h"
#import "UIImageView+WebCache.h"
typedef NS_ENUM(NSInteger, SPCarouseImagesDataStyle){
SPCarouseImagesDataInLocal,//本地图片标记
SPCarouseImagesDataInURL //URL图片标记
};
// width和height依赖于传进来的frame
#define kWidth self.bounds.size.width
#define kHeight self.bounds.size.height
@interface SPCarouselScrollView () <UIScrollViewDelegate>
@property(strong, nonatomic) UIScrollView *scrollView;
@property(strong, nonatomic) UIPageControl *pageControl;
// 存放本地图片名字的数组
@property(strong, nonatomic) NSArray<NSString *> *localImages;
//存放图片数组的网址
@property(strong, nonatomic) NSArray<NSString *> *urlImages;
// 前一个视图,当前视图,下一个视图
@property(strong, nonatomic) UIImageView *lastImgView;
@property(strong, nonatomic) UIImageView *currentImgView;
@property(strong, nonatomic) UIImageView *nextImgView;
// 图片来源(本地或URL)
@property(nonatomic) SPCarouseImagesDataStyle carouseImagesStyle;
@property(strong, nonatomic) NSTimer *timer;
// kCount = array.count,图片数组个数
@property(assign, nonatomic) NSInteger kCount;
// 记录nextImageView的下标 默认从1开始
@property(assign, nonatomic) NSInteger nextPhotoIndex;
// 记录lastImageView的下标 默认从 _kCount - 1 开始
@property(assign, nonatomic) NSInteger lastPhotoIndex;
@property(strong, nonatomic) UILabel *label;
@end
@implementation SPCarouselScrollView
#pragma mark - 初始化方法
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self initialize];
}
return self;
}
- (void)initialize {
_duration = 2;
_autoScroll = YES;
_pageControlColor = [UIColor grayColor];
_currentPageControlColor = [UIColor whiteColor];
}
#pragma mark - 类方法
// 如果是本地图片调用此方法
+(SPCarouselScrollView *)carouselScrollViewWithFrame:(CGRect)frame localImages:(NSArray<NSString *> *)localImages{
SPCarouselScrollView *carouseScroll =[[SPCarouselScrollView alloc]initWithFrame:frame];
// 调用set方法
carouseScroll.localImages = localImages;
return carouseScroll;
}
// 如果是网络图片调用此方法
+(SPCarouselScrollView *)carouselScrollViewWithFrame:(CGRect)frame urlImages:(NSArray<NSString *> *)urlImages{
SPCarouselScrollView *carouseScroll = [[SPCarouselScrollView alloc]initWithFrame:frame];
// 调用set方法
carouseScroll.urlImages = urlImages;
return carouseScroll;
}
#pragma mark - setter方法专区
// 是否自动轮播
- (void)setAutoScroll:(BOOL)autoScroll {
_autoScroll = autoScroll;
if (autoScroll) {
// 开启新的定时器
[self openTimer];
} else {
// 关闭定时器
[self closeTimer];
}
}
// 重写duration的set方法,用户可以在外界设置轮播图间隔时间
-(void)setDuration:(NSTimeInterval)duration{
_duration = duration;
[self openTimer];
}
// 设置其他小圆点的颜色
- (void)setPageControlColor:(UIColor *)pageControlColor {
_pageControlColor = pageControlColor;
_pageControl.pageIndicatorTintColor = pageControlColor;
}
// 设置当前小圆点的颜色
- (void)setCurrentPageControlColor:(UIColor *)currentPageControlColor {
_currentPageControlColor = currentPageControlColor;
_pageControl.currentPageIndicatorTintColor = currentPageControlColor;
}
// 设置其他小圆点的图片
- (void)setPageControlImage:(UIImage *)pageControlImage {
if (pageControlImage == nil) {
NSLog(@"Error:其余小圆点的图片为nil,请检查");
return;
}
_pageControlImage = pageControlImage;
[_pageControl setValue:_pageControlImage forKeyPath:@"pageImage"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (_currentPageControlImage == nil) {
NSLog(@"Error:您只设置了其余小圆点的图片,没有设置当前小圆点的图片");
}
});
}
// 设置当前小圆点的图片
- (void)setCurrentPageControlImage:(UIImage *)currentPageControlImage {
if (currentPageControlImage == nil) {
NSLog(@"Error:当前小圆点的图片为nil,请检查");
return;
}
_currentPageControlImage = currentPageControlImage;
[_pageControl setValue:_currentPageControlImage forKeyPath:@"currentPageImage"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (_pageControlImage == nil) {
NSLog(@"Error:您只设置了当前小圆点的图片,没有设置其他小圆点的图片");
}
});
}
// 设置pageControl的位置
- (void)setPageContolAliment:(SPCarouseScrollViewPageContolAliment)pageContolAliment {
_pageContolAliment = pageContolAliment;
switch (pageContolAliment) {
case SPCarouseScrollViewPageContolAlimentCenter:
// 如果是中间
_pageControl.frame = CGRectMake(0, 0, kWidth, 30);
_pageControl.center = CGPointMake(kWidth * 0.5, kHeight - 30 / 2);
break;
case SPCarouseScrollViewPageContolAlimentRight:
// 如果是右边
_pageControl.frame = CGRectMake(0, 0, kWidth, 30);
_pageControl.center = CGPointMake(kWidth * 0.5 * 1.5, kHeight - 30 / 2);
break;
case SPCarouseScrollViewPageContolAlimentLeft:
// 如果是左边
_pageControl.frame = CGRectMake(0, 0, kWidth, 30);
_pageControl.center = CGPointMake(kWidth * 0.5 * 0.5, kHeight - 30 / 2);
break;
default:
break;
}
}
// 设置imageView的内容模式
- (void)setImageMode:(SPCarouselScrollViewImageMode)imageMode {
_imageMode = imageMode;
switch (imageMode) {
case SPCarouselScrollViewImageModeScaleToFill:
_lastImgView.contentMode = UIViewContentModeScaleToFill;
_currentImgView.contentMode = UIViewContentModeScaleToFill;
_nextImgView.contentMode = UIViewContentModeScaleToFill;
break;
case SPCarouselScrollViewImageModeScaleAspectFit:
_lastImgView.contentMode = UIViewContentModeScaleAspectFit;
_currentImgView.contentMode = UIViewContentModeScaleAspectFit;
_nextImgView.contentMode = UIViewContentModeScaleAspectFit;
break;
case SPCarouselScrollViewImageModeScaleAspectFill:
_lastImgView.contentMode = UIViewContentModeScaleAspectFill;
_currentImgView.contentMode = UIViewContentModeScaleAspectFill;
_nextImgView.contentMode = UIViewContentModeScaleAspectFill;
break;
case SPCarouselScrollViewImageModeCenter:
_lastImgView.contentMode = UIViewContentModeCenter;
_currentImgView.contentMode = UIViewContentModeCenter;
_nextImgView.contentMode = UIViewContentModeCenter;
break;
default:
break;
}
}
- (void)setLocalImages:(NSArray<NSString *> *)localImages {
if (_localImages != localImages) {
_localImages = nil;
_localImages = localImages;
}
//标记图片来源
self.carouseImagesStyle = SPCarouseImagesDataInLocal;
//获取数组个数
self.kCount = _localImages.count;
[self drawMyView];
[self openTimer];
}
- (void)setUrlImages:(NSArray<NSString *> *)urlImages {
if (_urlImages != urlImages) {
_urlImages = nil;
_urlImages = urlImages;
}
//标记图片来源
self.carouseImagesStyle = SPCarouseImagesDataInURL;
self.kCount = _urlImages.count;
[self drawMyView];
[self openTimer];
}
#pragma maek - 其它方法
-(void)drawMyView{
[self addSubview:self.scrollView];
[self addSubview:self.pageControl];
self.nextPhotoIndex = 1;
self.lastPhotoIndex = _kCount - 1;
//想在轮播图上添加其他子控件可在这里添加
/*
self.label = [[UILabel alloc]initWithFrame:CGRectMake(50, 500,kWidth-100, 30)];
self.label.backgroundColor = [UIColor redColor];
[self addSubview:self.label];
*/
}
// 开启定时器
- (void)openTimer {
// 开启之前一定要先将上一次开启的定时器关闭,否则会跟新的定时器重叠
[self closeTimer];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.duration target:self selector:@selector(timerAction) userInfo:self repeats:YES];
// UITrackingRunLoopMode模式的作用是当用户拖动tableView、collectionView等事件时定时器仍然会处理事件
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
_timer = timer;
}
// 关闭定时器
- (void)closeTimer {
[_timer invalidate];
_timer = nil;
}
#pragma mark - 懒加载
-(UIScrollView *)scrollView{
if (_scrollView == nil) {
_scrollView = [[UIScrollView alloc]initWithFrame:self.bounds];
_scrollView.pagingEnabled = YES;
_scrollView.bounces = NO;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
_scrollView.contentSize = CGSizeMake(kWidth * 3, kHeight);
//显示中间的图片
_scrollView.contentOffset = CGPointMake(kWidth, 0);
_scrollView.delegate = self;
// 添加最初的三张imageView
[_scrollView addSubview:self.lastImgView];
[_scrollView addSubview:self.currentImgView];
[_scrollView addSubview:self.nextImgView];
}
return _scrollView;
}
-(UIPageControl *)pageControl{
if (_pageControl == nil) {
_pageControl = [[UIPageControl alloc]initWithFrame:CGRectMake(0, 0, kWidth, 30)];
_pageControl.center = CGPointMake(kWidth/2.0, kHeight - 30/2.0);
_pageControl.userInteractionEnabled = NO;
_pageControl.hidesForSinglePage = YES;
_pageControl.pageIndicatorTintColor = self.pageControlColor;
_pageControl.currentPageIndicatorTintColor = self.currentPageControlColor;
_pageControl.numberOfPages = self.kCount;
_pageControl.currentPage = 0;
}
return _pageControl;
}
-(UIImageView *)lastImgView{
if (_lastImgView == nil) {
_lastImgView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, kWidth, kHeight)];
// 一上来,将上一张图片设置为数组中最后一张图片
[self setImageView:_lastImgView withSubscript:(_kCount-1)];
}
return _lastImgView;
}
-(UIImageView *)currentImgView{
if (_currentImgView == nil) {
_currentImgView = [[UIImageView alloc]initWithFrame:CGRectMake(kWidth, 0, kWidth, kHeight)];
// 一上来,将当前图片设置为数组中第一张图片
[self setImageView:_currentImgView withSubscript:0];
// 给当前图片添加手势
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTapActionInImageView:)];
[_currentImgView addGestureRecognizer:tap];
_currentImgView.userInteractionEnabled = YES;
}
return _currentImgView;
}
-(UIImageView *)nextImgView{
if (_nextImgView == nil) {
_nextImgView = [[UIImageView alloc]initWithFrame:CGRectMake(kWidth*2, 0,kWidth , kHeight)];
// 一上来,将下一张图片设置为数组中第二张图片,如果数组只有一张图片,则上、中、下图片全部是数组中的第一张图片
[self setImageView:_nextImgView withSubscript:_kCount == 1 ? 0 : 1];
}
return _nextImgView;
}
//根据下标设置imgView的image
-(void)setImageView:(UIImageView *)imgView withSubscript:(NSInteger)subcript{
if (self.carouseImagesStyle == SPCarouseImagesDataInLocal) {
imgView.image = [UIImage imageNamed:self.localImages[subcript]];
} else{
//网络图片设置, 如果要使用占位图请自行修改
[imgView sd_setImageWithURL:[NSURL URLWithString:self.urlImages[subcript]] placeholderImage:nil];
}
}
#pragma mark - scrollView代理方法
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
//到第一张图片时 (一上来,当前图片的x值是kWidth)
if (scrollView.contentOffset.x <= 0) {
// 这个if语句只有scrollView往右滑时才有会进入
_nextImgView.image = _currentImgView.image;
_currentImgView.image = _lastImgView.image;
// 将轮播图的偏移量设回中间位置
scrollView.contentOffset = CGPointMake(kWidth, 0);
_lastImgView.image = nil;
// 一定要是小于等于,否则数组中只有一张图片时会出错
if (_lastPhotoIndex <= 0) {
_lastPhotoIndex = _kCount - 1;
_nextPhotoIndex = _lastPhotoIndex - (_kCount - 2);
} else {
_lastPhotoIndex--;
if (_nextPhotoIndex == 0) {
_nextPhotoIndex = _kCount - 1;
} else {
_nextPhotoIndex--;
}
}
[self setImageView:_lastImgView withSubscript:_lastPhotoIndex];
}
// 到最后一张图片时(最后一张就是轮播图的第三张)
if (scrollView.contentOffset.x >= kWidth*2) {
// 这个if语句只有scrollView往左滑时才会进入
_lastImgView.image = _currentImgView.image;
_currentImgView.image = _nextImgView.image;
// 将轮播图的偏移量设回中间位置
scrollView.contentOffset = CGPointMake(kWidth, 0);
_nextImgView.image = nil;
// 一定要是大于等于,否则数组中只有一张图片时会出错
if (_nextPhotoIndex >= _kCount - 1 ) {
_nextPhotoIndex = 0;
_lastPhotoIndex = _nextPhotoIndex + (_kCount - 2);
} else{
_nextPhotoIndex++;
if (_lastPhotoIndex == _kCount - 1) {
_lastPhotoIndex = 0;
} else {
_lastPhotoIndex++;
}
}
[self setImageView:_nextImgView withSubscript:_nextPhotoIndex];
}
}
// scrollView结束减速的时候调用
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//矫正pageCotrol的位置
_pageControl.currentPage = _nextPhotoIndex - 1;
if (_nextPhotoIndex - 1 < 0) {
_pageControl.currentPage = _kCount-1;
}
;
}
// 用户将要拖拽时将定时器关闭
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
// 关闭定时器
[self closeTimer];
}
// 用户结束拖拽时将定时器开启(在打开自动轮播的前提下)
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (self.autoScroll) {
[self openTimer];
}
}
#pragma mark - timer事件
-(void)timerAction{
// 一上来,轮播图显示的是中间的那张图片,定时器每次触发都让当前图片为轮播图的第三张ImageView的image
[_scrollView setContentOffset:CGPointMake(2*kWidth, 0) animated:YES];
_pageControl.currentPage = _nextPhotoIndex;
}
#pragma mark - 手势点击事件
-(void)handleTapActionInImageView:(UITapGestureRecognizer *)tap {
if (_delegate && [_delegate respondsToSelector:@selector(carouseScrollView:atIndex:)]) {
// 如果_nextPhotoIndex == 0,那么中间那张图片一定是数组中最后一张,我们要传的就是中间那张图片在数组中的下标
if (_nextPhotoIndex == 0) {
[_delegate carouseScrollView:self atIndex:_kCount-1];
}else{
[_delegate carouseScrollView:self atIndex:_nextPhotoIndex-1];
}
}
}
#pragma mark - 系统方法
-(void)willMoveToSuperview:(UIView *)newSuperview {
if (!newSuperview) {
[self closeTimer];
}
}
-(void)dealloc {
_scrollView.delegate = nil;
}
@end
浙公网安备 33010602011771号