IOS实现自动循环滚动广告--ScrollView的优化和封装

jopen 10年前

一、问题分析

在许多App中,我们都会见到循环滚动的视图,比如广告,其实想实现这个功能并不难,用ScrollView就可以轻松完成,但是在制作的过程中还存在几个小问题,如果能够正确的处理好这些小问题,无论从效果还是性能上都会得到优化。

问题一

第一个问题是如何用ScrollView来展示N个视图。想要实现这个效果,可以把N个视图依次按顺序添加到ScrollView上,然后把 ScrollView的contentSize设置为N个视图的尺寸,通过滑动ScrollView来查看加在上面的视图。

问题二

第二个问题是如何完成图片的循环滚动,也就是展示完最后一张之后会接着展示第一张,形成图片的循环展示。想要实现这个效果,首先需要让ScrollView实现自动分页,这样可以保证滑动结束展示的是完整的视图;其次,需要根据当前展示的页数来设置ScrollView的contentOffset。

对于第一个问题的解决是用的最简单的方式,但实际上忽略了一个很重要的问题,那就是如果要展示的视图数量N非常大的时候,我们该如何做呢?假设通过ScrollView来展示的每个视图的宽度恰好是屏幕的宽度,那么在展示的时候,其实能够呈现在我们眼前的最多只有两个视图,也就是要么是完整的一个视图,要么是两个不完整的视图。因此,我们只需要有三个视图,就能够完成循环的展示。

问题三

第三个问题是在循环滚动的过程中,希望知道当前的页数,这个页数可以通过contentOffset.x来计算,通常会用UIPageControl来表示。此外,当点击某一个视图的时候,要能够知道当前点击的视图是哪一个。

问题四

第四个问题是自动展示下一页的功能,这个需要写好跳到下一页的方法,然后通过NSTimer定时器来完成。

除了上面的几个问题,大家也可以为其添加更多的功能。那么对于ScrollView自动翻页这样通用的功能,最好的方式是将其封装起来,这样可以大大的提高效率。下面的代码是把UIScrollView、UIPageControl封装到了一个UIView中,而其中的ScrollView用来循环展示多张图片。

二、功能实现

1、封装Scrollview代码.h:

//  WHScrollAndPageView.h  //  循环滚动视图  //  //  Created by jereh on 15-3-15.  //  Copyright (c) 2015年 jereh. All rights reserved.  //    #import <UIKit/UIKit.h>    @protocol WHcrollViewViewDelegate;    @interface WHScrollAndPageView : UIView <UIScrollViewDelegate>  {      __unsafe_unretained id <WHcrollViewViewDelegate> _delegate;  }    @property (nonatomic, assign) id <WHcrollViewViewDelegate> delegate;    @property (nonatomic, assign) NSInteger currentPage;    @property (nonatomic, strong) NSMutableArray *imageViewAry;    @property (nonatomic, readonly) UIScrollView *scrollView;    @property (nonatomic, readonly) UIPageControl *pageControl;    -(void)shouldAutoShow:(BOOL)shouldStart;    @end    @protocol WHcrollViewViewDelegate <NSObject>    @optional  - (void)didClickPage:(WHScrollAndPageView *)view atIndex:(NSInteger)index;    @end

2、封装Scrollview代码.m:

//  WHScrollAndPageView.m  //  循环滚动视图  //  //  Created by jereh on 15-3-15.  //  Copyright (c) 2015年 jereh. All rights reserved.  //    #import "WHScrollAndPageView.h"    @interface WHScrollAndPageView ()  {      UIView *_firstView;      UIView *_middleView;      UIView *_lastView;            float _viewWidth;      float _viewHeight;            NSTimer *_autoScrollTimer;            UITapGestureRecognizer *_tap;  }    @end    @implementation WHScrollAndPageView    - (id)initWithFrame:(CGRect)frame  {      self = [super initWithFrame:frame];      if (self) {                _viewWidth = self.bounds.size.width;          _viewHeight = self.bounds.size.height;                    //设置scrollview          _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, _viewWidth, _viewHeight)];          _scrollView.delegate = self;          _scrollView.contentSize = CGSizeMake(_viewWidth * 3, _viewHeight);          _scrollView.showsHorizontalScrollIndicator = NO;          _scrollView.pagingEnabled = YES;          _scrollView.backgroundColor = [UIColor blackColor];          _scrollView.delegate = self;          [self addSubview:_scrollView];                    //设置分页          _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, _viewHeight-30, _viewWidth, 30)];          _pageControl.userInteractionEnabled = NO;          _pageControl.currentPageIndicatorTintColor = [UIColor redColor];          _pageControl.pageIndicatorTintColor = [UIColor whiteColor];          [self addSubview:_pageControl];                    //设置单击手势          _tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];          _tap.numberOfTapsRequired = 1;          _tap.numberOfTouchesRequired = 1;          [_scrollView addGestureRecognizer:_tap];      }      return self;  }    #pragma mark 单击手势  -(void)handleTap:(UITapGestureRecognizer*)sender  {      if ([_delegate respondsToSelector:@selector(didClickPage:atIndex:)]) {          [_delegate didClickPage:self atIndex:_currentPage+1];      }  }    #pragma mark 设置imageViewAry  -(void)setImageViewAry:(NSMutableArray *)imageViewAry  {      if (imageViewAry) {          _imageViewAry = imageViewAry;          _currentPage = 0; //默认为第0页                    _pageControl.numberOfPages = _imageViewAry.count;      }            [self reloadData];  }    #pragma mark 刷新view页面  -(void)reloadData  {      [_firstView removeFromSuperview];      [_middleView removeFromSuperview];      [_lastView removeFromSuperview];            //从数组中取到对应的图片view加到已定义的三个view中      if (_currentPage==0) {          _firstView = [_imageViewAry lastObject];          _middleView = [_imageViewAry objectAtIndex:_currentPage];          _lastView = [_imageViewAry objectAtIndex:_currentPage+1];      }      else if (_currentPage == _imageViewAry.count-1)      {          _firstView = [_imageViewAry objectAtIndex:_currentPage-1];          _middleView = [_imageViewAry objectAtIndex:_currentPage];          _lastView = [_imageViewAry firstObject];      }      else      {          _firstView = [_imageViewAry objectAtIndex:_currentPage-1];          _middleView = [_imageViewAry objectAtIndex:_currentPage];          _lastView = [_imageViewAry objectAtIndex:_currentPage+1];      }            //设置三个view的frame,加到scrollview上      _firstView.frame = CGRectMake(0, 0, _viewWidth, _viewHeight);      _middleView.frame = CGRectMake(_viewWidth, 0, _viewWidth, _viewHeight);      _lastView.frame = CGRectMake(_viewWidth*2, 0, _viewWidth, _viewHeight);      [_scrollView addSubview:_firstView];      [_scrollView addSubview:_middleView];      [_scrollView addSubview:_lastView];            //设置当前的分页      _pageControl.currentPage = _currentPage;            //显示中间页      _scrollView.contentOffset = CGPointMake(_viewWidth, 0);  }    #pragma mark scrollvie停止滑动  -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView  {      //手动滑动时候暂停自动替换      [_autoScrollTimer invalidate];      _autoScrollTimer = nil;      _autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES];            //得到当前页数      float x = _scrollView.contentOffset.x;            //往前翻      if (x<=0) {          if (_currentPage-1<0) {              _currentPage = _imageViewAry.count-1;          }else{              _currentPage --;          }      }            //往后翻      if (x>=_viewWidth*2) {          if (_currentPage==_imageViewAry.count-1) {              _currentPage = 0;          }else{              _currentPage ++;          }      }            [self reloadData];  }    #pragma mark 自动滚动  -(void)shouldAutoShow:(BOOL)shouldStart  {      if (shouldStart)  //开启自动翻页      {          if (!_autoScrollTimer) {              _autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES];          }      }      else   //关闭自动翻页      {          if (_autoScrollTimer.isValid) {              [_autoScrollTimer invalidate];              _autoScrollTimer = nil;          }      }  }    #pragma mark 展示下一页  -(void)autoShowNextImage  {      if (_currentPage == _imageViewAry.count-1) {          _currentPage = 0;      }else{          _currentPage ++;      }            [self reloadData];  }    @end

3、使用封装好的Scrollview代码.m:

//  ViewController.m  //  循环滚动视图  //  //  Created by jereh on 15-3-15.  //  Copyright (c) 2015年 jereh. All rights reserved.  //    #import "ViewController.h"  #import "WHScrollAndPageView.h"  #define NUM 10    @interface ViewController ()<WHcrollViewViewDelegate>  {      WHScrollAndPageView *_whView;  }    @end    @implementation ViewController    - (void)viewDidLoad  {      [super viewDidLoad];            //创建view (view中包含UIScrollView、UIPageControl,设置frame)      _whView = [[WHScrollAndPageView alloc] initWithFrame:CGRectMake(0, 44, 320, 400)];            //把N张图片放到imageview上      NSMutableArray *tempAry = [NSMutableArray array];      for (int i=1; i<NUM; i++) {          UIImageView *imageView = [[UIImageView alloc] init];          imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"image%i.jpg",i]];          [tempAry addObject:imageView];      }            //把imageView数组存到whView里      [_whView setImageViewAry:tempAry];            //把图片展示的view加到当前页面      [self.view addSubview:_whView];            //开启自动翻页      [_whView shouldAutoShow:YES];            //遵守协议      _whView.delegate = self;  }    #pragma mark 协议里面方法,点击某一页  -(void)didClickPage:(WHScrollAndPageView *)view atIndex:(NSInteger)index  {      NSLog(@"点击了第%li页",index);  }    #pragma mark 界面消失的时候,停止自动滚动  -(void)viewDidDisappear:(BOOL)animated  {      [_whView shouldAutoShow:NO];  }    @end