[关闭]
@whiteiOS 2017-01-10T12:23:38.000000Z 字数 5664 阅读 1168

scrollView轮播图(三个imageView)

iOS学习之路


一、原理

一共有3个imageView,初始化状态看到的是位于3个imageView中间的第一张图片,此时scrollView的contentOffsetX等于width,然后左边是最后一张图片,右边是第二张图片。如果用户向左滑动显示第二张图片,当第二张图片完全显示出来后,此时scrollView的contentOffsetX等于2*width,我们要做的第一件事就是将用户移动的位置进行复位,也就是让scrollView的contentOffsetX变回width,然后重新设置每个imageView应该显示的图片,因为代码执行速度很快,所以你意识不到它的切换。这样左边的imageView显示的是当前图片的上一张图片,右边的imageView显示的是当前图片的下一张图片,如下图所示

二、代码实现

先自定义一个view继承自UIView,作为封装的轮播图类

CXInfiniteScrollView.m中

(一)初始化添加子控件

  1. //UIImageView的个数
  2. static NSUInteger const CXImageViewCout = 3;
  3. /*
  4. * 初始化:添加子控件
  5. */
  6. - (instancetype)initWithFrame:(CGRect)frame
  7. {
  8. if (self = [super initWithFrame:frame]) {
  9. _scrollInterval = 2.0;
  10. _animationInterval = 1.0;
  11. //添加scrollView对象
  12. UIScrollView *scrollView = [[UIScrollView alloc] init];
  13. scrollView.backgroundColor = [UIColor clearColor];
  14. scrollView.showsHorizontalScrollIndicator = NO;
  15. scrollView.showsVerticalScrollIndicator = NO;
  16. scrollView.pagingEnabled = YES;
  17. scrollView.delegate = self;
  18. scrollView.bounces = NO;
  19. [self addSubview:scrollView];
  20. self.scrollView = scrollView;
  21. //添加3个UIImageView对象
  22. for (NSUInteger i = 0; i < CXImageViewCout; i++) {
  23. UIImageView *imageView = [[UIImageView alloc] init];
  24. imageView.contentMode = UIViewContentModeScaleToFill;
  25. [scrollView addSubview:imageView];
  26. }
  27. //添加pageControl对象
  28. UIPageControl *pageControl = [[UIPageControl alloc] init];
  29. [self addSubview:pageControl];
  30. pageControl.currentPageIndicatorTintColor = [UIColor redColor];
  31. self.pageControl = pageControl;
  32. }
  33. return self;
  34. }

(二)布局子控件

  1. /*
  2. * 布局子控件
  3. */
  4. - (void)layoutSubviews
  5. {
  6. [super layoutSubviews];
  7. //scrollView
  8. self.scrollView.frame = self.bounds;
  9. //pageControl
  10. CGSize pageSize = [self.pageControl sizeForNumberOfPages:_imageNames.count];
  11. CGFloat pageControlX = (self.bounds.size.width - pageSize.width) / 2;
  12. CGFloat pageControlY = self.bounds.size.height - pageSize.height;
  13. self.pageControl.frame = CGRectMake(pageControlX, pageControlY, pageSize.width, pageSize.height);
  14. //imageView
  15. CGFloat imageW = self.scrollView.frame.size.width;
  16. CGFloat imageH = self.scrollView.frame.size.height;
  17. for (NSUInteger i = 0; i < CXImageViewCout; i++) {
  18. UIImageView *imageView = self.scrollView.subviews[i];
  19. imageView.frame = CGRectMake(i * imageW, 0, imageW, imageH);
  20. }
  21. self.scrollView.contentOffset = CGPointMake(imageW, 0);
  22. self.scrollView.contentSize = CGSizeMake(imageW * CXImageViewCout, 0);
  23. }

(三)属性的set方法

  1. /*
  2. * 根据传入的图片数组设置图片
  3. */
  4. - (void)setImageNames:(NSArray *)imageNames
  5. {
  6. _imageNames = imageNames;
  7. self.pageControl.numberOfPages = imageNames.count;
  8. //更新UIImageView内容
  9. [self updateContent];
  10. //开启定时器
  11. [self startTimer];
  12. }

注意:要在该方法中更新UIImageView内容,意思是获取到图片后接着更新UIImageView,之前在别的地方调用的updateContent,导致scrollView老是等好几秒才显示网络图片,弄了好久才发现是这的问题

(四)设置UIImageView的内容

  1. /*
  2. * 更新UIImageView内容
  3. */
  4. - (void)updateContent
  5. {
  6. //从左到右重新设置每个imageView的图片内容
  7. for (NSUInteger i = 0; i < CXImageViewCout; i++) {
  8. UIImageView *imageView = self.scrollView.subviews[i];
  9. //为了设置imageView对应的图片索引
  10. NSInteger imageIndex = 0;
  11. if (i == 0) { //最左边的imageView
  12. imageIndex = self.pageControl.currentPage - 1;
  13. } else if (i == 2) { //最右边的imageView
  14. imageIndex = self.pageControl.currentPage + 1;
  15. } else {
  16. imageIndex = self.pageControl.currentPage;
  17. }
  18. //无限循环的处理
  19. if (imageIndex == -1) { //当上面的imageIndex为0时,如果再向右拖动,左侧图片显示,应该让它显示为最后一张图片
  20. imageIndex = self.imageNames.count - 1;
  21. } else if (imageIndex == self.imageNames.count) { //当上面的imageIndex超过最大图片数量时,也就是滑到最右再继续滑动的时候,让它显示第一张图片
  22. imageIndex = 0;
  23. }
  24. //判断是URL还是本地图片
  25. NSString *imageName = self.imageNames[imageIndex];
  26. if (imageName) {
  27. if ([self verifyURL:imageName]) {
  28. NSURL *url = [NSURL URLWithString:imageName];
  29. [imageView sd_setImageWithURL:url];
  30. } else {
  31. imageView.image = [UIImage imageNamed:imageName];
  32. }
  33. }
  34. //绑定图片索引到imageView的tag
  35. imageView.tag = imageIndex;
  36. }
  37. //scrollView的contentOffset(偏移量归位)
  38. self.scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width, 0);
  39. }
  40. /*
  41. * 判断是否是URL
  42. */
  43. - (BOOL)verifyURL:(NSString *)url
  44. {
  45. NSString *pattern = @"((http|ftp|https)://)(([a-zA-Z0-9\\._-]+\\.[a-zA-Z]{2,6})|([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9\\&%_\\./-~-]*)?";
  46. NSPredicate *p = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
  47. BOOL isMatch = [p evaluateWithObject:url];
  48. return isMatch;
  49. }

(五)scrollView代理方法的设置

  1. /*
  2. * 拖拽的时候
  3. */
  4. - (void)scrollViewDidScroll:(UIScrollView *)scrollView
  5. {
  6. //拖动的时候,哪张图片最靠中间,也就是偏移量最小,就滑到哪页
  7. // imageView的x 和 scrollView偏移量x 的最小差值
  8. CGFloat minDelta = MAXFLOAT; //MAXFLOAT:最大浮点数
  9. // 找出显示在最中间的图片索引
  10. NSInteger centerImageIndex = 0;
  11. for (NSUInteger i = 0; i < CXImageViewCout; i++) {
  12. UIImageView *imageView = self.scrollView.subviews[i];
  13. // ABS : 取得绝对值
  14. CGFloat delta = ABS(imageView.frame.origin.x - self.scrollView.contentOffset.x);
  15. if (delta < minDelta) {
  16. minDelta = delta;
  17. centerImageIndex = imageView.tag;
  18. }
  19. }
  20. // 设置页码
  21. self.pageControl.currentPage = centerImageIndex;
  22. }
  23. /*
  24. * 拖拽开始时停止定时器
  25. */
  26. - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
  27. {
  28. [self stopTimer];
  29. }
  30. /*
  31. * 拖拽结束时开启定时器
  32. */
  33. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
  34. {
  35. [self startTimer];
  36. }
  37. /*
  38. * 减速停止的时候更新图片
  39. */
  40. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
  41. {
  42. [self updateContent];
  43. }

(六)设置定时器

  1. /*
  2. * 开启定时器
  3. */
  4. - (void)startTimer
  5. {
  6. if (!_timer) {
  7. _timer = [NSTimer scheduledTimerWithTimeInterval:_scrollInterval target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
  8. }
  9. }
  10. /*
  11. * 停止定时器
  12. */
  13. - (void)stopTimer
  14. {
  15. [self.timer invalidate];
  16. //计时器被系统强引用,必须手动释放
  17. self.timer = nil;
  18. }
  19. /*
  20. * 显示下一页
  21. */
  22. - (void)nextPage
  23. {
  24. [UIView animateWithDuration:_animationInterval animations:^{
  25. self.scrollView.contentOffset = CGPointMake(2 * self.scrollView.frame.size.width, 0);
  26. } completion:^(BOOL finished) {
  27. //更新视图
  28. [self updateContent];
  29. }];
  30. }

(七)对外的接口

  1. @interface CXInfiniteScrollView : UIView
  2. @property (nonatomic, strong) NSArray *imageNames;
  3. /** 切换图片的时间间隔 */
  4. @property (nonatomic, assign) CGFloat scrollInterval;
  5. /** 切换图片动画的时长 */
  6. @property (nonatomic, assign) CGFloat animationInterval;
  7. @end

(八)外界调用

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. NSArray *images = @[@"001.jpg", @"002.jpg", @"003.jpg", @"004.jpg"];
  4. CXInfiniteScrollView *scroll = [[CXInfiniteScrollView alloc] initWithFrame:CGRectMake(0, 0, 375, 200)];
  5. scroll.imageNames = images;
  6. [self.view addSubview:scroll];
  7. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注