转载自 http://www.jianshu.com/p/aa73c273baf2数组
咱们会常常用到循环滚动图片,包括定时滚动,点击触发事件。
之前所知道的循环滚动图片的方法是这样的。好比:一共5张图片,位置为1,2,3,4,5。网络
imageView
。scrollViewDidScroll
的代理方法里面判断scrollView.contentOffset.x>320*6-1
,将scrollView
的偏移量设置为320
的位置,动画设置为NO
。320*6
,这个值是大于320*6-1
的,进入到if
语句,将scrollView
设置320
的位置,则就是第一个图片1的位置,这样就形成一个视觉差,是从最后一张图片滚动到第一张图片的。之前是那么用的,可是后来以为这样比较占资源,也比较麻烦,如今是这样的,无论多少张图片只建立3个imageView
。app
viewController
中取到图片数据源,建立当前须要展现的图片数组长度是3,当前展现的图片位置默认是0。320
,滑动到下一张图片的时候,设置当前位置为1,设置当前数组图片为图片一、图片二、图片3,刷新UI,而且把scrollView
的偏移量设置为320
,即展现的图片永远在中间。#import <UIKit/UIKit.h> @protocol CycleScrollViewDelegate; @interface CycleScrollView : UIView<UIScrollViewDelegate>
数据源ide
@property (nonatomic, strong) NSArray *imageArray;
滚动视图。原本是不须要这个属性的,可是有个问题:若是图片正好滚动了一半app进入到后台,再次打开的时候是滚动到一半状态,滚动到下一张图片的时候就行了,因此把这个问题在viewController
里面处理。oop
@property (nonatomic, strong) UIScrollView *scrollView; @property (nonatomic, weak) id<CycleScrollViewDelegate> delegate; @end
代理方法动画
@protocol CycleScrollViewDelegate <NSObject> - (void)cycleScrollView:(CycleScrollView *)cycleScrollView didSelectImageView:(NSInteger)index; @end
#import "CycleScrollView.h" #import "ImageModel.h" //图片model #import "UIImageView+WebCache.h" //SDWebImage设置网络图片 #define c_width (self.bounds.size.width+10) //两张图片以前有10点的间隔 #define c_height (self.bounds.size.height) @implementation CycleScrollView { UIPageControl *_pageControl; //分页控件 NSMutableArray *_curImageArray; //当前显示的图片数组 NSInteger _curPage; //当前显示的图片位置 NSTimer *_timer; //定时器 }
重写init
方法atom
- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { //滚动视图 self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, c_width, c_height)]; self.scrollView.contentSize = CGSizeMake(c_width*3, 0); self.scrollView.contentOffset = CGPointMake(c_width, 0); self.scrollView.pagingEnabled = YES; self.scrollView.showsHorizontalScrollIndicator = NO; self.scrollView.delegate = self; [self addSubview:self.scrollView]; //分页控件 _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, c_height-30, self.bounds.size.width, 30)]; _pageControl.userInteractionEnabled = NO; _pageControl.hidesForSinglePage = YES; _pageControl.currentPageIndicatorTintColor = [UIColor redColor]; _pageControl.pageIndicatorTintColor = [UIColor grayColor]; [self addSubview:_pageControl]; //初始化数据,当前图片默认位置是0 _curImageArray = [[NSMutableArray alloc] initWithCapacity:0]; _curPage = 0; } return self; }
scrollView
的代理方法url
#pragma mark - UIScrollViewDelegate - (void)scrollViewDidScroll:(UIScrollView *)scrollView { //若是scrollView当前偏移位置x大于等于两倍scrollView宽度 if (scrollView.contentOffset.x >= c_width*2) { //当前图片位置+1 _curPage++; //若是当前图片位置超过数组边界,则设置为0 if (_curPage == [self.imageArray count]) { _curPage = 0; } //刷新图片 [self reloadData]; //设置scrollView偏移位置 [scrollView setContentOffset:CGPointMake(c_width, 0)]; } //若是scrollView当前偏移位置x小于等于0 else if (scrollView.contentOffset.x <= 0) { //当前图片位置-1 _curPage--; //若是当前图片位置小于数组边界,则设置为数组最后一张图片下标 if (_curPage == -1) { _curPage = [self.imageArray count]-1; } //刷新图片 [self reloadData]; //设置scrollView偏移位置 [scrollView setContentOffset:CGPointMake(c_width, 0)]; } } //中止滚动的时候回调 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { //设置scrollView偏移位置 [scrollView setContentOffset:CGPointMake(c_width, 0) animated:YES]; }
重写图片数组的set
方法代理
- (void)setImageArray:(NSMutableArray *)imageArray { _imageArray = imageArray; //设置分页控件的总页数 _pageControl.numberOfPages = imageArray.count; //刷新图片 [self reloadData]; //开启定时器 if (_timer) { [_timer invalidate]; _timer = nil; } //判断图片长度是否大于1,若是一张图片不开启定时器 if ([imageArray count] > 1) { _timer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(timerScrollImage) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode]; [[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate date]]; } }
刷新图片的方法code
- (void)reloadData { //设置页数 _pageControl.currentPage = _curPage; //根据当前页取出图片 [self getDisplayImagesWithCurpage:_curPage]; //从scrollView上移除全部的subview NSArray *subViews = [self.scrollView subviews]; if ([subViews count] > 0) { [subViews makeObjectsPerformSelector:@selector(removeFromSuperview)]; } //建立imageView for (int i = 0; i < 3; i++) { UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(c_width*i, 0, self.bounds.size.width, c_height)]; imageView.userInteractionEnabled = YES; [self.scrollView addSubview:imageView]; //设置网络图片 ImageModel *model = _curImageArray[i]; NSURL *url = [NSURL URLWithString:model.image_url]; [imageView sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:@"placeholder_320x120.png"]]; //tap手势 UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapImage:)]; [imageView addGestureRecognizer:tap]; } }
获取图片
- (void)getDisplayImagesWithCurpage:(NSInteger)page { //取出开头和末尾图片在图片数组里的下标 NSInteger front = page - 1; NSInteger last = page + 1; //若是当前图片下标是0,则开头图片设置为图片数组的最后一个元素 if (page == 0) { front = [self.imageArray count]-1; } //若是当前图片下标是图片数组最后一个元素,则设置末尾图片为图片数组的第一个元素 if (page == [self.imageArray count]-1) { last = 0; } //若是当前图片数组不为空,则移除全部元素 if ([_curImageArray count] > 0) { [_curImageArray removeAllObjects]; } //当前图片数组添加图片 [_curImageArray addObject:self.imageArray[front]]; [_curImageArray addObject:self.imageArray[page]]; [_curImageArray addObject:self.imageArray[last]]; }
定时器的方法
- (void)timerScrollImage { //刷新图片 [self reloadData]; //设置scrollView偏移位置 [self.scrollView setContentOffset:CGPointMake(c_width*2, 0) animated:YES]; }
tap
图片的方法
- (void)tapImage:(UITapGestureRecognizer *)tap { //设置代理 if ([_delegate respondsToSelector:@selector(cycleScrollView:didSelectImageView:)]) { [_delegate cycleScrollView:self didSelectImageView:_curPage]; } }
dealloc
方法
- (void)dealloc { //代理指向nil,关闭定时器 self.scrollView.delegate = nil; [_timer invalidate]; } @end
viewController里面的代码
#import "CycleScrollView.h" @interface RootViewController:BaseViewController<CycleScrollViewDelegate> @property (nonatomic, strong) CycleScrollView *imageScrollView; self.imageScrollView = [[CycleScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)]; self.imageScrollView.delegate = self; [headerView addSubview:self.imageScrollView];
获取到的网络数据方法里,设置循环滚动图片的图片数组
if ( [[resultDict objectForKey:@"big_image_list"] count] > 0) { self.imageArray = [resultDict objectForKey:@"big_image_list"]; self.imageScrollView.imageArray = self.imageArray; }
代理方法回调
#pragma mark - CycleScrollViewDelegate - (void)cycleScrollView:(CycleScrollView *)cycleScrollView didSelectImageView:(NSInteger)index { NSLog(@"点击了第%ld张图片",(long)index+1); ImageModel *model = self.imageArray[index]; }
处理图片正好滚动了一半app进入到后台,再次打开的时候是滚动到一半状态的问题。
- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; //设置图片循环滚动,若是偏移位置大于330,则设置为330 if (self.imageScrollView.scrollView.contentOffset.x > 330) { self.imageScrollView.scrollView.contentOffset = CGPointMake(330*2, 0); } }