案例:
(1)用storyboard布局,这里用了三样东西。
——UIScrollView就是我们准备存放滚动图片的容器。
——Page Control就是控制页数的那几个小点点。可以设置有多少个点,当前点和其他点的颜色等。注意它和UIScrollView是平级的,不是它的子视图。
——还有一个textView是带有滚动的,用来测试多线程的。暂且随意拖放在页面中即可。
(2)在ViewController.m中
——借助之前的scrollView属性,设置滚动范围
——借助新学习的scrollView的属性pagingEnabled直接设置scrollView是否分页。这里面需要注意的是,如果要借助这种方式实现分页,那么最好让scrollView的宽度正好等于里面每张图片的宽度,否则分页会出现截断。因为分页是按照scrollView的宽度给整个滚动区域做切割的。
——借助showsHorizontalScrollIndicator属性去除水平滚动条,垂直滚动条的属性,输入showsVe....查看,这里略去。
——借助定时器,实现每隔1秒钟播放下一张图片的效果。
——这里同样用到代理:
因为我们需要监听scrollView滚动到哪里:以设置响应的Page Control的当前点点。
因为我们需要监听scrollView是否被拖拽,如果被拖拽,那么就停止那个定时器。
因为我们需要监听scrollView是否停止被拖拽,如果不被拖拽,那么要重新添加一个定时器。
——当然,这里面定时器每隔1秒播放下一张图片,其实是定时器每隔1秒执行一次imagePlay方法,这个imagePlay方法主要通过改变scrollView的contentOffset值来实现scrollView的滚动。
#import "ViewController.h" @interface ViewController ()<UIScrollViewDelegate> @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; @property (weak, nonatomic) IBOutlet UIPageControl *pageControl; @property (strong,nonatomic) NSTimer *timer; @end @implementation ViewController //总共图片数量 #define kIMGCOUNT 5 - (void)viewDidLoad { CGFloat imageY=0; CGFloat imageW=self.scrollView.frame.size.width; CGFloat imageH=self.scrollView.frame.size.height; //用for循环往ScrollView中添加图片,这里面计算每张图片的x值是重点 for (int i=0; i<kIMGCOUNT; i++) { UIImageView *imageView=[[UIImageView alloc]init]; CGFloat imageX=i*imageW; imageView.frame=CGRectMake(imageX, imageY, imageW, imageH); imageView.image=[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d",i+1]]; [self.scrollView addSubview:imageView]; } //然后设置scrollView的contentSize,这样才能滚动起来,这里滚动只有横向滚动,所以竖向的为0 self.scrollView.contentSize=CGSizeMake(kIMGCOUNT*imageW, 0); //分页,pagingEnabled是scrollView的一个属性 self.scrollView.pagingEnabled=YES; //去除水平滚动条 self.scrollView.showsHorizontalScrollIndicator=NO; //设置页数控制器总页数,即按钮数 self.pageControl.numberOfPages=kIMGCOUNT; //设置代理 self.scrollView.delegate=self; //设置自动播放,定时器。每隔1秒钟播放下一张图片 [self timerOn]; [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } //比方下一张图片,其实就是拖动scrollView,也就是改变scrollView的contentOffset属性 //当然,这里要判断一下,如果播放最后一张了,那么下一张就是第一张 -(void)imgPlay{ int i=self.pageControl.currentPage; if (i==kIMGCOUNT-1) { i=-1; } i++; [self.scrollView setContentOffset:CGPointMake(i*self.scrollView.frame.size.width, 0) animated:YES]; } //当用户准备拖拽的时候,关闭定时器 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ [self timerOff]; } //当用户停止拖拽的时候,添加一个定时器 -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ [self timerOn]; } //每隔1秒播放图片,其实是每隔1秒调用imgPlay方法 -(void)timerOn{ self.timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(imgPlay) userInfo:nil repeats:YES]; //为了防止单线程的弊端,可以保证用户在使用其他控件的时候系统照样可以让定时器运转 [[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes]; } //关闭定时器,并且把定时器设置为nil,这是习惯 -(void)timerOff{ [self.timer invalidate]; self.timer=nil; } //这个事判断定时器滚动的时候,实时判断滚动位置,以让Page Controll显示当前的点是哪一个点 //这个需要在总宽度上加上半个scrollView的宽度,是为了保证拖拽到一半时候左右的效果 -(void)scrollViewDidScroll:(UIScrollView *)scrollView{ self.pageControl.currentPage=(self.scrollView.frame.size.width*0.5+self.scrollView.contentOffset.x)/self.scrollView.frame.size.width; } @end
当然,这里面的代码是经过一些封装的。
比如,我们把开关定时器封装成两个方法,这样哪里用到只需要调用以下即可。
(3)Page Control,其实就是一些小点点,你可以设置当前处于第几个点,一共有几个点,当前点得颜色,其他点得颜色等等。
(4)这里面涉及到了一个多线程的知识。
一般我们值面向单线程,即系统每次只能处理一个事件,比如我们这里的图片轮播,如果用户在页面上拖拽其他东西,比如我们这里的textView,那么系统就会集中处理这个事件,无暇顾及我们的图片轮播,所以这个时候图片轮播就不动了。
我们要介绍的时NSRunLoop这个类。它是什么呢?其实看了很多他人的笔记,大家只说了它的作用功能,但是连最基本的翻译都没有,翻看官方文档,我们可以把它理解成是一个专门用来接受用户一些输入操作的台子。一般而言,单线程的话,这个台子只能接受一个操作。所以才会出现我们上面的情况。
要解决这个问题的思路就在于:我们先拿到当前的台子 >>> 然后把我们的定时器死乞白赖地添加到这个台子里 >>> 相当于我们这个定时器也时时刻刻被系统处理着,不会因为其他事件而忽略定时器。
[[NSRunLoop currentRunLoop]addTimer:self.timer forMode:NSRunLoopCommonModes];