iOS --- 轮播图

在iOS开发中,有很多项目使用到了轮播图,通常我们更多的是使用一些别人写的方法来实现,当然这样也更加快捷和方便,但其中的实现原理却一窍不通,最近对轮播图研究了一番,也试着去实现了一些基本的功能,下面就让我来介绍一下:

本文中的轮播图主要是实用UIScrollView + NSTimer来实现的,具体思路是:首先我们先创建一个UIScrollView,根据图片的数据设置UIScrollView的内容尺寸(因为要实现无限轮播的的效果,需要多设置一个宽度的内容尺寸来起到缓冲的作用,使其显示到最后一张时,当我们再次滑动,直接跳转到第一张,即UIScrollView的内容尺寸为图片数据总和再加1,下面会详细介绍),然后创建一个UIPageControl来现实图片的具体位置,并让其与UIScrollView起到联动的效果。最后创建一个定时器,每隔一段时间设置UIScrollView的偏移量,注意也要更改UIPageControl的选中页位置。当然这种方法主要适用于数据较少的时候使用,当数据较多时,我们就要考虑复用的问题了。

首先确定数据源,这里我们使用本地数据,创建图片数组来存放五张图片

1  _imgArray = @[@"01.jpg", @"02.jpg", @"03.jpg", @"04.jpg", @"05.jpg"];

创建UIScrollView和UIPageControl,注意UIScrollView的内容尺寸为_imgArray.count + 1,UIScrollView的最后一个位置要放置地一张图片

 1 _scrollView = [[UIScrollView alloc]initWithFrame:CGRctMake(0, 0, kScreenWidth, 200)];
 2     _scrollView.contentSize = CGSizeMake(kScreenWidth * (_imgArray.count + 1), 200);
 3     _scrollView.pagingEnabled = YES;
 4     _scrollView.delegate = self;
 5     _scrollView.showsHorizontalScrollIndicator = NO;
 6     //创建子视图
 7     for (int i = 0; i < _imgArray.count + 1; i++) {
 8         UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0 + i * kScreenWidth, 0, kScreenWidth, 200)];
 9         if (i == _imgArray.count) {
10             imgView.image = [UIImage imageNamed:_imgArray[0]];
11         }else{
12           imgView.image = [UIImage imageNamed:_imgArray[i]];
13         } 
14         [_scrollView addSubview:imgView];
15     }
16     [self.view addSubview:_scrollView];
17     
18     //创建分页控件
19     _pageCtrl = [[UIPageControl alloc]initWithFrame:CGRectMake((kScreenWidth - 130)/2, _scrollView.bottom - 20, 130, 15)];
20     //_pageCtrl.backgroundColor = [UIColor cyanColor];
21     _pageCtrl.numberOfPages = _imgArray.count;
22     _pageCtrl.currentPage = 0;
23     [self.view addSubview:_pageCtrl];

实现UIScrollView的代理方法 - (void)scrollViewDidScroll:(UIScrollView *)scrollView,在此方法中可以获取到scrollView的偏移量,根据偏移量获取分页位置。假设屏幕宽度为320,根据上图可明显得出,当向右滑动xOff为1600时,UIScrollView恰好滑到了最后一个索引处,即第一张图片。此时如果我们不添加处理,继续向右滑动,没有图片,这不是我们想要的结果。无限循环滑动才是我们的目的,此时,我们想看到的是第二张图片,索引为1。因此,当xOff大于1600 的瞬间,设置UIScrollView的偏移量为CGPointMake(0, 0),此时我们看到的仍然是第一张图片,但是已经实现了循环跳转,只是我们肉眼难以察觉。注意,设置偏移量时animate要设置为NO。同理,当向左滑动xOff为0时,继续滑动,我们想要看到的是第五张图片,索引为4。因此当xOff小于0时,设置设置UIScrollView的偏移量为CGPointMake(1600, 0),此时我们看到的仍然是第一张图片(第六张图片,索引5)。注意,在此处处理UIPageControl的选中页位置。

 

 1 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
 2     CGFloat xOff = scrollView.contentOffset.x;
 3     int index = xOff/kScreenWidth;
 4     
 5     if (index == 5) {
 6         _pageCtrl.currentPage = 0;
 7     }else{
 8         _pageCtrl.currentPage = index;
 9     }
10     //    0      1      2      3       4       0
11     // 0    320    640    960    1280    1600
12     if (xOff > kScreenWidth * _imgArray.count) {
13      
14         [scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
15     
16     }
17     if (xOff < 0) {
18         [scrollView setContentOffset:CGPointMake(kScreenWidth * _imgArray.count, 0) animated:NO];
19     }
20     
21 }

至此,轮播图的基本工功能,我们已经大致实现了。下面,我们添加一个定时器,使UIScrollView能够根据定时器每隔1s自动滚动:

      number = 0;
    _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(setOffsetMethod) userInfo:nil repeats:YES];


- (void)setOffsetMethod{
    
    number++;
    [_scrollView setContentOffset:CGPointMake(kScreenWidth * number, 0) animated:YES];
    
}

要注意当滚动到最后一个索引时,使number= 0;

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    CGFloat xOff = scrollView.contentOffset.x;
    int index = xOff/kScreenWidth;
    
    if (index == 5) {
        _pageCtrl.currentPage = 0;
    }else{
        _pageCtrl.currentPage = index;
    }
    //    0      1      2      3       4       0
    // 0    320    640    960    1280    1600
    if (xOff > kScreenWidth * _imgArray.count) {
        number = 0;
        [scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
    
    }
    if (xOff < 0) {
        [scrollView setContentOffset:CGPointMake(kScreenWidth * _imgArray.count, 0) animated:NO];
    }
    
}

接下来有一个重要问题就是解决定时器与滑动手势的冲突,实现下面两个代理方法:

//开始拖动
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    NSLog(@"开始拖动");
    [_timer setFireDate:[NSDate distantFuture]];
}
//结束拖动
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
    NSLog(@"结束拖动");
    int index = scrollView.contentOffset.x/kScreenWidth;
    number = index;
    [_timer setFireDate:[NSDate date]];
}

下面是轮播图项目的全部代码:

  1 //  轮播图
  2 
  3 #import "Test02ViewController.h"
  4 #import "UIViewExt.h"
  5 #import "Test01ViewController.h"
  6 
  7 @interface Test02ViewController ()<UIScrollViewDelegate>
  8 {
  9     NSInteger number;
 10 }
 11 @property(nonatomic, strong)UIScrollView *scrollView;
 12 @property(nonatomic, strong)NSArray *imgArray;
 13 @property(nonatomic, strong)UIPageControl *pageCtrl;
 14 
 15 @property(nonatomic, strong)NSTimer *timer;
 16 
 17 @end
 18 
 19 @implementation Test02ViewController
 20 
 21 - (void)viewDidLoad {
 22     [super viewDidLoad];
 23     // Do any additional setup after loading the view.
 24     self.view.backgroundColor = [UIColor whiteColor];
 25     self.navigationController.navigationBar.translucent = NO;
 26     _imgArray = @[@"01.jpg", @"02.jpg", @"03.jpg", @"04.jpg", @"05.jpg"];
 27     [self addSubViews];
 28     NSLog(@"viewDidLoad");
 29 }
 30 
 31 - (void)viewWillAppear:(BOOL)animated{
 32     [super viewWillAppear:animated];
 33     [_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
 34 
 35 }
 36 - (void)viewDidAppear:(BOOL)animated{
 37     [super viewDidAppear:animated];
 38 
 39     number = 0;
 40     _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(setOffsetMethod) userInfo:nil repeats:YES];
 41 }
 42 - (void)viewWillDisappear:(BOOL)animated{
 43     [super viewWillDisappear:animated];
 44     
 45     [_timer invalidate];
 46 }
 47 
 48 - (void)addSubViews{
 49     _scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, 200)];
 50     _scrollView.contentSize = CGSizeMake(kScreenWidth * (_imgArray.count + 1), 200);
 51     _scrollView.pagingEnabled = YES;
 52     _scrollView.delegate = self;
 53     _scrollView.showsHorizontalScrollIndicator = NO;
 54     //创建子视图
 55     for (int i = 0; i < _imgArray.count + 1; i++) {
 56         UIImageView *imgView = [[UIImageView alloc]initWithFrame:CGRectMake(0 + i * kScreenWidth, 0, kScreenWidth, 200)];
 57         if (i == _imgArray.count) {
 58             imgView.image = [UIImage imageNamed:_imgArray[0]];
 59         }else{
 60           imgView.image = [UIImage imageNamed:_imgArray[i]];
 61         }
 62         UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
 63         [tap addTarget:self action:@selector(touchAction)];
 64         [imgView addGestureRecognizer:tap];
 65         imgView.userInteractionEnabled = YES;
 66         
 67         [_scrollView addSubview:imgView];
 68     }
 69     [self.view addSubview:_scrollView];
 70     
 71     //创建分页控件
 72     _pageCtrl = [[UIPageControl alloc]initWithFrame:CGRectMake((kScreenWidth - 130)/2, _scrollView.bottom - 20, 130, 15)];
 73     //_pageCtrl.backgroundColor = [UIColor cyanColor];
 74     _pageCtrl.numberOfPages = _imgArray.count;
 75     _pageCtrl.currentPage = 0;
 76     [self.view addSubview:_pageCtrl];
 77     
 78 }
 79 - (void)touchAction{
 80     NSLog(@"点击");
 81     [_timer setFireDate:[NSDate distantFuture]];
 82     [self pushVC];
 83 }
 84 
 85 #pragma mark -UIScrollViewDelegate
 86 //已经滑动
 87 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
 88     CGFloat xOff = scrollView.contentOffset.x;
 89     int index = xOff/kScreenWidth;
 90     
 91     if (index == 5) {
 92         _pageCtrl.currentPage = 0;
 93     }else{
 94         _pageCtrl.currentPage = index;
 95     }
 96     //    0      1      2      3       4       0
 97     // 0    320    640    960    1280    1600
 98     if (xOff > kScreenWidth * _imgArray.count) {
 99         number = 0;
100         [scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
101     
102     }
103     if (xOff < 0) {
104         [scrollView setContentOffset:CGPointMake(kScreenWidth * _imgArray.count, 0) animated:NO];
105     }
106     
107 }
108 - (void)setOffsetMethod{
109     
110     number++;
111     [_scrollView setContentOffset:CGPointMake(kScreenWidth * number, 0) animated:YES];
112     
113 }
114 //开始拖动
115 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
116     NSLog(@"开始拖动");
117     [_timer setFireDate:[NSDate distantFuture]];
118 }
119 //结束拖动
120 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
121     NSLog(@"结束拖动");
122     int index = scrollView.contentOffset.x/kScreenWidth;
123     number = index;
124     [_timer setFireDate:[NSDate date]];
125 }
126 - (void)pushVC{
127     Test01ViewController *test01VC = [[Test01ViewController alloc]init];
128     [self.navigationController pushViewController:test01VC animated:YES];
129 }
130 
131 
132 
133 - (void)didReceiveMemoryWarning {
134     [super didReceiveMemoryWarning];
135     // Dispose of any resources that can be recreated.
136 }
137 
138 /*
139 #pragma mark - Navigation
140 
141 // In a storyboard-based application, you will often want to do a little preparation before navigation
142 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
143     // Get the new view controller using [segue destinationViewController].
144     // Pass the selected object to the new view controller.
145 }
146 */
147 
148 @end
View Code

 

posted @ 2017-04-13 10:21  hongsheng  阅读(409)  评论(0编辑  收藏  举报