一、问题分析 |
在许多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 // WHScrollAndPageView.h 2 // 循环滚动视图 3 // 4 // Created by jereh on 15-3-15. 5 // Copyright (c) 2015年 jereh. All rights reserved. 6 // 7 8 #import <uikit uikit.h=""> 9 10 @protocol WHcrollViewViewDelegate; 11 12 @interface WHScrollAndPageView : UIView <uiscrollviewdelegate> 13 { 14 __unsafe_unretained id <whcrollviewviewdelegate> _delegate; 15 } 16 17 @property (nonatomic, assign) id <whcrollviewviewdelegate> delegate; 18 19 @property (nonatomic, assign) NSInteger currentPage; 20 21 @property (nonatomic, strong) NSMutableArray *imageViewAry; 22 23 @property (nonatomic, readonly) UIScrollView *scrollView; 24 25 @property (nonatomic, readonly) UIPageControl *pageControl; 26 27 -(void)shouldAutoShow:(BOOL)shouldStart; 28 29 @end 30 31 @protocol WHcrollViewViewDelegate <nsobject> 32 33 @optional 34 - (void)didClickPage:(WHScrollAndPageView *)view atIndex:(NSInteger)index; 35 36 @end</nsobject></whcrollviewviewdelegate></whcrollviewviewdelegate></uiscrollviewdelegate></uikit>
1 // WHScrollAndPageView.m 2 // 循环滚动视图 3 // 4 // Created by jereh on 15-3-15. 5 // Copyright (c) 2015年 jereh. All rights reserved. 6 // 7 8 #import "WHScrollAndPageView.h" 9 10 @interface WHScrollAndPageView () 11 { 12 UIView *_firstView; 13 UIView *_middleView; 14 UIView *_lastView; 15 16 float _viewWidth; 17 float _viewHeight; 18 19 NSTimer *_autoScrollTimer; 20 21 UITapGestureRecognizer *_tap; 22 } 23 24 @end 25 26 @implementation WHScrollAndPageView 27 28 - (id)initWithFrame:(CGRect)frame 29 { 30 self = [super initWithFrame:frame]; 31 if (self) { 32 33 _viewWidth = self.bounds.size.width; 34 _viewHeight = self.bounds.size.height; 35 36 //设置scrollview 37 _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, _viewWidth, _viewHeight)]; 38 _scrollView.delegate = self; 39 _scrollView.contentSize = CGSizeMake(_viewWidth * 3, _viewHeight); 40 _scrollView.showsHorizontalScrollIndicator = NO; 41 _scrollView.pagingEnabled = YES; 42 _scrollView.backgroundColor = [UIColor blackColor]; 43 _scrollView.delegate = self; 44 [self addSubview:_scrollView]; 45 46 //设置分页 47 _pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, _viewHeight-30, _viewWidth, 30)]; 48 _pageControl.userInteractionEnabled = NO; 49 _pageControl.currentPageIndicatorTintColor = [UIColor redColor]; 50 _pageControl.pageIndicatorTintColor = [UIColor whiteColor]; 51 [self addSubview:_pageControl]; 52 53 //设置单击手势 54 _tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)]; 55 _tap.numberOfTapsRequired = 1; 56 _tap.numberOfTouchesRequired = 1; 57 [_scrollView addGestureRecognizer:_tap]; 58 } 59 return self; 60 } 61 62 #pragma mark 单击手势 63 -(void)handleTap:(UITapGestureRecognizer*)sender 64 { 65 if ([_delegate respondsToSelector:@selector(didClickPage:atIndex:)]) { 66 [_delegate didClickPage:self atIndex:_currentPage+1]; 67 } 68 } 69 70 #pragma mark 设置imageViewAry 71 -(void)setImageViewAry:(NSMutableArray *)imageViewAry 72 { 73 if (imageViewAry) { 74 _imageViewAry = imageViewAry; 75 _currentPage = 0; //默认为第0页 76 77 _pageControl.numberOfPages = _imageViewAry.count; 78 } 79 80 [self reloadData]; 81 } 82 83 #pragma mark 刷新view页面 84 -(void)reloadData 85 { 86 [_firstView removeFromSuperview]; 87 [_middleView removeFromSuperview]; 88 [_lastView removeFromSuperview]; 89 90 //从数组中取到对应的图片view加到已定义的三个view中 91 if (_currentPage==0) { 92 _firstView = [_imageViewAry lastObject]; 93 _middleView = [_imageViewAry objectAtIndex:_currentPage]; 94 _lastView = [_imageViewAry objectAtIndex:_currentPage+1]; 95 } 96 else if (_currentPage == _imageViewAry.count-1) 97 { 98 _firstView = [_imageViewAry objectAtIndex:_currentPage-1]; 99 _middleView = [_imageViewAry objectAtIndex:_currentPage]; 100 _lastView = [_imageViewAry firstObject]; 101 } 102 else 103 { 104 _firstView = [_imageViewAry objectAtIndex:_currentPage-1]; 105 _middleView = [_imageViewAry objectAtIndex:_currentPage]; 106 _lastView = [_imageViewAry objectAtIndex:_currentPage+1]; 107 } 108 109 //设置三个view的frame,加到scrollview上 110 _firstView.frame = CGRectMake(0, 0, _viewWidth, _viewHeight); 111 _middleView.frame = CGRectMake(_viewWidth, 0, _viewWidth, _viewHeight); 112 _lastView.frame = CGRectMake(_viewWidth*2, 0, _viewWidth, _viewHeight); 113 [_scrollView addSubview:_firstView]; 114 [_scrollView addSubview:_middleView]; 115 [_scrollView addSubview:_lastView]; 116 117 //设置当前的分页 118 _pageControl.currentPage = _currentPage; 119 120 //显示中间页 121 _scrollView.contentOffset = CGPointMake(_viewWidth, 0); 122 } 123 124 #pragma mark scrollvie停止滑动 125 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 126 { 127 //手动滑动时候暂停自动替换 128 [_autoScrollTimer invalidate]; 129 _autoScrollTimer = nil; 130 _autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES]; 131 132 //得到当前页数 133 float x = _scrollView.contentOffset.x; 134 135 //往前翻 136 if (x<=0) { 137 if (_currentPage-1<0) { 138 _currentPage = _imageViewAry.count-1; 139 }else{ 140 _currentPage --; 141 } 142 } 143 144 //往后翻 145 if (x>=_viewWidth*2) { 146 if (_currentPage==_imageViewAry.count-1) { 147 _currentPage = 0; 148 }else{ 149 _currentPage ++; 150 } 151 } 152 153 [self reloadData]; 154 } 155 156 #pragma mark 自动滚动 157 -(void)shouldAutoShow:(BOOL)shouldStart 158 { 159 if (shouldStart) //开启自动翻页 160 { 161 if (!_autoScrollTimer) { 162 _autoScrollTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(autoShowNextImage) userInfo:nil repeats:YES]; 163 } 164 } 165 else //关闭自动翻页 166 { 167 if (_autoScrollTimer.isValid) { 168 [_autoScrollTimer invalidate]; 169 _autoScrollTimer = nil; 170 } 171 } 172 } 173 174 #pragma mark 展示下一页 175 -(void)autoShowNextImage 176 { 177 if (_currentPage == _imageViewAry.count-1) { 178 _currentPage = 0; 179 }else{ 180 _currentPage ++; 181 } 182 183 [self reloadData]; 184 } 185 186 @end
1 // ViewController.m 2 // 循环滚动视图 3 // 4 // Created by jereh on 15-3-15. 5 // Copyright (c) 2015年 jereh. All rights reserved. 6 // 7 8 #import "ViewController.h" 9 #import "WHScrollAndPageView.h" 10 #define NUM 10 11 12 @interface ViewController ()<whcrollviewviewdelegate> 13 { 14 WHScrollAndPageView *_whView; 15 } 16 17 @end 18 19 @implementation ViewController 20 21 - (void)viewDidLoad 22 { 23 [super viewDidLoad]; 24 25 //创建view (view中包含UIScrollView、UIPageControl,设置frame) 26 _whView = [[WHScrollAndPageView alloc] initWithFrame:CGRectMake(0, 44, 320, 400)]; 27 28 //把N张图片放到imageview上 29 NSMutableArray *tempAry = [NSMutableArray array]; 30 for (int i=1; i<num; _whview="" _whview.delegate="self;" animated="" imageview="[[UIImageView" imageview.image="[UIImage" index="" mark="" nsstring="" pragma="" pre="" self.view="" tempary="" uiimageview="" view="" whscrollandpageview=""><p> </p></num;></whcrollviewviewdelegate>