四:关于通过UIPageControl+UIScrollView实现图片循环轮播
网上关于这个功能实在是太多了,虽然很多都是很详细的,但是让人感觉总是一股脑就在那整体来实现,也就是说没有针对这个功能作下具体划分子功能,然后来让人更加明白其原理,所以再参考了很多长篇大论之后,依据个人理解,总结了一下。
关于这个功能,其实可以细分为如下几个小功能:
1.使用UIScrollView实现滑动时图片可分页轮播。
2.实现在UIScrollView中图片的循环轮播。
3.实现UIScrollView中图片的自动轮播。
4.加上UIPageControl控件之后,可以使该控件中的指示小点和UIScrollView的不同页进行对应。
5.当用户点击UIPageControl控件时,可以使该控件自身的指示小点变化的同时,触发UIScrollView相应的页面进行滑动。
下面针对以上几个子功能分别讲述下我自身的理解:
1.使用UIScrollView实现滑动时图片可分页轮播
这个功能很简单,在storyboard添加好UIScrollView之后,然后在其对应的controller的viewDidLoad方法中分别水平依次添加UIImageView,使所添加的每个UIImageView的长度高度和UIScrollView长度高度相同,Y偏移量为0,X的偏移量依次为(0,1,2,3...)个UIImageView的宽度,即达到所有的UIImageView水平无缝排列。最后设置UIScrollView的pagingEnabled属性为YES即可。示例代码如下:
#import "MyViewController.h"
@interface MyViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
@property (retain, nonatomic) NSArray * imageNameList;
@end
@implementation MyViewController
- (void) viewDidLoad{
[super viewDidLoad];
//得到scrollview的初始位置以及大小
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat imageH = self.scrollview.frame.size.height;
CGFloat imageInitialY = 0;
CGFloat imageInitialX = 0;
//设置分页图片的名字List
imageNameList = [[NSArray alloc] initWithObjects: @"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg",nil];
//分别设置分页图片的大小位置,然后添加至scrollview
for(int i=0; i< [imageNameList count]; i++){
UIImageView *imageView = [[UIImageView alloc] init];
CGFloat imageX = i*imageW + imageInitialX;
imageView.frame = CGRectMake(imageX, imageInitialY, imageW, imageH);
[imageView setImage:[UIImage imageNamed:[imageNameList objectAtIndex:i]]];
[self.scrollview addSubview:imageView];
}
//设置scrollview的content size
CGFloat contentW = totalCount *imageW;
self.scrollview.contentSize = CGSizeMake(contentW, 0);
//设置scrollview 的分页属性为YES,这样滚动时就以页面为单位进行滚动了
self.scrollview.pagingEnabled = YES;
}
ps:在本例中通过scrollview来获取得到的大小imageW和imageH从实际运作来看,无论运行在何种分辨率的apple设备上,貌似都是600,正好是storyboard设置面板的大小.这个问题后续我再研究研究,做个课题.
这个功能的原理主要是在所要展示的所有图片前后分别额外加第一张和最后一张图片,比如一共三张图片1,2,3,然后在图片1前加一张图片3,在图片3之后加一张图片1,即最终在scrollview一共依次添加3,1,2,3,1五张图片(具体添加步骤见功能1);添加好之后,然后让UIScrollView的controller实现protocal<UIScrollViewDelegate>(主要是实现该protocol的scrollViewDidScroll,scrollViewWillBeginDragging,scrollViewDidEndDragging等几个scrollview代理的比较重要的方法),并将该controller成为scrollview的delegate,因为当UIScrollView在进行滚动的时候就会调用其代理的scrollViewDidScroll方法,所以就可以在controller中控制scrollview滚动时的相关逻辑.而本功能中要用的就是控制当scrollview滚动到第五张图片(即图片1)时,然后调整scrollview的offset,使其偏移至第二张图片(即图片1),调整是设置animated为NO,就会让用户在视觉上感觉没有任何移动;同理当滚动到第一张图片(即图片3)的时候,调整其偏移,使其偏移值第四张图片(即图片3).示例代码如下(在功能1的基础上进行修改添加):
MyViewController.h代码:
#import <UIKit/UIKit.h>
@interface MyViewController : UIViewController<UIScrollViewDelegate>
@end
MyViewController.m代码:
#import "MyViewController.h"
@interface MyViewController ()
@property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
@property (retain, nonatomic) NSArray * imageNameList;
@end
@implementation MyViewController
- (void) viewDidLoad{
[super viewDidLoad];
//得到scrollview的初始位置以及大小
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat imageH = self.scrollview.frame.size.height;
CGFloat imageInitialY = 0;
CGFloat imageInitialX = 0;
//设置分页图片的名字List
imageNameList = [[NSArray alloc] initWithObjects: @"4.jpg",@"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg",@"1.jpg",nil];
//分别设置分页图片的大小位置,然后添加至scrollview
for(int i=0; i< [imageNameList count]; i++){
UIImageView *imageView = [[UIImageView alloc] init];
CGFloat imageX = i*imageW + imageInitialX;
imageView.frame = CGRectMake(imageX, imageInitialY, imageW, imageH);
[imageView setImage:[UIImage imageNamed:[imageNameList objectAtIndex:i]]];
[self.scrollview addSubview:imageView];
}
//设置scrollview的content size
CGFloat contentW = totalCount *imageW;
self.scrollview.contentSize = CGSizeMake(contentW, 0);
//设置scrollview 的分页属性为YES,这样滚动时就以页面为单位进行滚动了
self.scrollview.pagingEnabled = YES;
//设置scrollview的delegate为self
self.scrollview.delegate = self;
}
- (void) scrollViewDidScroll: (UIScrollView*) scrollview{
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat currentOffsetX = scrollview.contentOffset.x;
if(currentOffsetX ==0.0){
[scrollview setContentOffset:CGPointMake(imageW*4, 0) animated:NO];
}else if(currentOffsetX == imageX*5){
[scrollview setContentOffset:CGPointMake(imageW, 0) animated:NO];
}
}
3.实现UIScrollView中图片的自动轮播
这个功能主要是引入一个循环定时器,然后在本controller中定义一个方法,该方法主要实现把scrollview往下一个图片进行偏移(当然中间和功能2一样得考虑到循环滚动的逻辑),接着指定该定时器超时的时候调用此方法,最后需要明确一下,何时创建该定时器(在viewDidLoad中,这样可以保证一开始就能启动定时器达到自动轮播),何时停止该定时器(在scrollViewWillBeginDragging中停止这样可以达到当用户进行拖曳的时候定时器释放不会自动轮播),何时又该重启该定时器(在scrollViewDidEndDragging:willDecelerate中重启,这样可以达到当用户停止拖曳之后又能重启定时器来达到自动轮播). 示例代码如下:
#import "MyViewController.h"
@interface MyViewController ()
{
NSTimer *aotuScrollTimer;
}
@property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
@property (retain, nonatomic) NSArray * imageNameList;
@end
@implementation MyViewController
- (void) aotuScrollToNext: (NSTimer*) timer{
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat currentOffsetX = self.scrollview.contentOffset.x;
if(currentOffsetX == imageX*4){
[self.scrollview setContentOffset:CGPointMake(imageW, 0) animated:YES];
}else{
[self.scrollview setContentOffset:CGPointMake(currentOffsetX+imageW, 0) animated:YES];
}
}
- (void) viewDidLoad{
[super viewDidLoad];
//得到scrollview的初始位置以及大小
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat imageH = self.scrollview.frame.size.height;
CGFloat imageInitialY = 0;
CGFloat imageInitialX = 0;
//设置分页图片的名字List
imageNameList = [[NSArray alloc] initWithObjects: @"4.jpg",@"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg",@"1.jpg",nil];
//分别设置分页图片的大小位置,然后添加至scrollview
for(int i=0; i< [imageNameList count]; i++){
UIImageView *imageView = [[UIImageView alloc] init];
CGFloat imageX = i*imageW + imageInitialX;
imageView.frame = CGRectMake(imageX, imageInitialY, imageW, imageH);
[imageView setImage:[UIImage imageNamed:[imageNameList objectAtIndex:i]]];
[self.scrollview addSubview:imageView];
}
//设置scrollview的content size
CGFloat contentW = totalCount *imageW;
self.scrollview.contentSize = CGSizeMake(contentW, 0);
//设置scrollview 的分页属性为YES,这样滚动时就以页面为单位进行滚动了
self.scrollview.pagingEnabled = YES;
//设置scrollview的delegate为self
self.scrollview.delegate = self;</span>
//启动轮播定时器,间隔3秒
aotuScrollTimer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(aotuScrollToNext:) userInfo:nil repeats:YES];
}
- (void) scrollViewDidScroll: (UIScrollView*) scrollview{
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat currentOffsetX = self.scrollview.contentOffset.x;
if(currentOffsetX ==0.0){
[self.scrollview setContentOffset:CGPointMake(imageW*4, 0) animated:NO];
}else if(currentOffsetX == imageX*5){
[self.scrollview setContentOffset:CGPointMake(imageW, 0) animated:NO];
}
}
- (void) scrollViewWillBeginDragging: (UIScrollView*) scrollview{
//当用户准备拖曳时停止定时器,以后重启需重新启动,不会自动启动
[aotuScrollTimer invalidate];
}
- (void) scrollViewDidEndDragging: (UIScrollView*) scrollview{
//当用户停止拖曳时,定时器重启,自动轮播开始
aotuScrollTimer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(aotuScrollToNext:) userInfo:nil repeats:YES];
}
4.加上UIPageControl控件之后,可以使该控件中的指示小点和UIScrollView的不同页进行对应
该功能的主要实现原理主要是在添加了UIPageControl之后,根据图片的总数(当然不包括我们特意为实现功能2所额外加的两张重复图片)来设置UIPageControl的dot数,然后根据当前scrollview的偏移量来计算具体应该显示第几个dotscrollViewDidScrollaotuScrollToNext),然后设置为UIPageControl的currentpage即可。示例代码如下:
#import "MyViewController.h"
@interface MyViewController ()
{
NSTimer *aotuScrollTimer;
}
@property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
@property (retain, nonatomic) NSArray * imageNameList;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
@end
@implementation MyViewController
- (void) aotuScrollToNext: (NSTimer*) timer{
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat currentOffsetX = self.scrollview.contentOffset.x;
int currentPage;
if(currentOffsetX == imageX*4){
[self.scrollview setContentOffset:CGPointMake(imageW, 0) animated:YES];
}else{
[self.scrollview setContentOffset:CGPointMake(currentOffsetX+imageW, 0) animated:YES];
}
if(currentOffsetX<(imageW*0.5)){
currentPage = 4;
}else if(currentOffsetX>=(imageW*4.5)){
currentPage = 1;
}else{
currentPage = (int) (currentOffsetX+imageW*0.5)/imageW;
}
self.pageControl.currentPage = currentPage;
}
- (void) viewDidLoad{
[super viewDidLoad];
//得到scrollview的初始位置以及大小
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat imageH = self.scrollview.frame.size.height;
CGFloat imageInitialY = 0;
CGFloat imageInitialX = 0;
//设置分页图片的名字List
imageNameList = [[NSArray alloc] initWithObjects: @"4.jpg",@"1.jpg",@"2.jpg",@"3.jpg",@"4.jpg",@"1.jpg",nil];
//分别设置分页图片的大小位置,然后添加至scrollview
for(int i=0; i< [imageNameList count]; i++){
UIImageView *imageView = [[UIImageView alloc] init];
CGFloat imageX = i*imageW + imageInitialX;
imageView.frame = CGRectMake(imageX, imageInitialY, imageW, imageH);
[imageView setImage:[UIImage imageNamed:[imageNameList objectAtIndex:i]]];
[self.scrollview addSubview:imageView];
}
//设置scrollview的content size
CGFloat contentW = totalCount *imageW;
self.scrollview.contentSize = CGSizeMake(contentW, 0);
//设置scrollview 的分页属性为YES,这样滚动时就以页面为单位进行滚动了
self.scrollview.pagingEnabled = YES;
//设置scrollview的delegate为self
self.scrollview.delegate = self;
//启动轮播定时器,间隔3秒
aotuScrollTimer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(aotuScrollToNext:) userInfo:nil repeats:YES];
}
- (void) scrollViewDidScroll: (UIScrollView*) scrollview{
CGFloat imageW = self.scrollview.frame.size.width;
CGFloat currentOffsetX = self.scrollview.contentOffset.x;
int currentPage;
if(currentOffsetX ==0.0){
[self.scrollview setContentOffset:CGPointMake(imageW*4, 0) animated:NO];
}else if(currentOffsetX == imageX*5){
[self.scrollview setContentOffset:CGPointMake(imageW, 0) animated:NO];
}
if(currentOffsetX<(imageW*0.5)){
currentPage = 4;
}else if(currentOffsetX>=(imageW*4.5)){
currentPage = 1;
}else{
currentPage = (int) (currentOffsetX+imageW*0.5)/imageW;
}
self.pageControl.currentPage = currentPage;
}
- (void) scrollViewWillBeginDragging: (UIScrollView*) scrollview{
//当用户准备拖曳时停止定时器,以后重启需重新启动,不会自动启动
[aotuScrollTimer invalidate];
}
- (void) scrollViewDidEndDragging: (UIScrollView*) scrollview{
//当用户停止拖曳时,定时器重启,自动轮播开始
aotuScrollTimer = [NSTimer scheduledTimerWithTimeInterval:3.0f target:self selector:@selector(aotuScrollToNext:) userInfo:nil repeats:YES];
}
5.当用户点击UIPageControl控件时,可以使该控件自身的指示小点变化的同时,触发UIScrollView相应的页面进行滑动
待续。。。。。