本文共 6235 字,大约阅读时间需要 20 分钟。
@property(nonatomic) NSInteger numberOfPages;
@property(nonatomic) NSInteger currentPage;
@property(nonatomic) BOOL hidesForSinglePage;ssssss
@property(nonatomic,retain) UIColor *pageIndicatorTintColor;
@property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;
在指定的时间执行指定的任务
每隔一段时间执行指定的任务调用下面的方法就会开启一个定时任务
+(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
每隔ti秒,调用一次aTarget的aSelector方法,yesOrNo决定了是否重复执行这个任务
通过invalidate方法可以停止定时器的工作,一旦定时器被停止了,就不能再次执行任务。只能再创建一个新的定时器才能执行新的任务- (void)invalidate;
添加 UIScrollView
创建一个UIScrollView, 设置宽为300, 高为130 (与每张图片的大小一致)动态向 UIScrollView 中添加图片框(横向)
向UIScrollView中添加内容(要滚动的内容, 添加到UIScrollView的子控件集合中) –循环添加5个UIImageView, 设置图片, 设置 frame设置 UIScrollView 的 contentSize 实现滚动, 实现横向滚动
设置UIScrollView的contentSize的width为5个图片的总大小, 上下不滚动所以height为0实现分页
只要将UIScrollView的pageEnabled属性设置为YES,UIScrollView会被分割成多个独立页面,里面的内容就能进行分页展示 去掉水平滚动条 –self.scrollView.showsHorizontalScrollIndicator = NO;问题: 设置完pagingEnabled = YES以后,scrollView是怎么知道该如何分页的?
答: 按照UIScrollView自身的宽度来实现分页的.UIScrollView的宽度就是每页的大小。实现分页指示器 UIPageControl
通过UIPageControl来实现 拽一个UIPageControl放到控制器的view中, 不要放到UIScrollView中, 否则就一起滚动了. 设置UIPageControl的Tint Color(其他页颜色)和Current Page(当前页颜色)属性颜色 注意: 当把UIPageControl添加到控制器的view中的时候, 这个控件和UIScrollView根本没有任何联系, 所以没有分页指示功能通过使用 Nstimer 实现自动滚动
在 viewDidLoad 中启动定时器 启动定时器的两种方法: 1> 调用timerWithXxx创建的timer,把这个timer对象手动加到”消息循环”中才能启动 2> 调用scheduledTimerWithXxx创建的timer,自动启动(创建完毕后自动启动)。实现分页指示器总页数、当前页。
–总页数: numberOfPages属性 self.pageControl.numberOfPages = imageCount; –当前页: currentPage属性 •self.pageControl.currentPage = 0; •注意: –在 viewDidLoad 中设置总页数 –在- (void)scrollViewDidScroll:代理方法中设置当前页 –设置当前页的思路: •通过当前的滚动的偏移值来计算出当前滚动到第几页了在该方法中根据UIScrollView滚动到第几张图片,然后设置Page Control 当前第几个点显示为current page
当前页 = (当前滚动的偏移contentOffset.x + 半个图片的宽度) / 每个图片的宽度 ** 问题: 为什么要用偏移加半个宽度? 设想: 如果contentOffset.x小于半个宽度,那么加上半个宽度以后除以图片宽度,结果还是0 如果contentOffset大于半个宽度,那么加上半个宽度以后除以一个宽度,结果还是1. 公式代码: int page = (scrollView.contentOffset.x + 0.5 * scrollView.frame.size.width)/ scrollView.frame.size.width; self.pageControl.currentPage = page;
//代理方法- (void)scrollViewDidScroll:(UIScrollView *)scrollView{int page = (scrollView.contentOffset.x + 0.5 * scrollView.frame.size.width)/ scrollView.frame.size.width;self.pageControl.currentPage = page;}
1> NSTimer(时间间隔比较大1秒,几秒)
2> CADisplayLink(时间间隔比较小,0.0几秒等)在这里我们选择的是NSTimer定时器
创建、启动定时器代码参考:// 方式一[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];// 方式二// 创建 NSTimer 对象NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES];// 将刚创建的 NSTimer 对象加到消息循环中, 这样就会自动启动定时器NSRunLoop *runLoop = [NSRunLoop currentRunLoop];[runLoop addTimer:timer forMode:NSRunLoopCommonModes];// 方式三// 创建计时器对象NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(test1) userInfo:nil repeats:YES]// 每次调用一次 fire 执行一次 test1方法[timer fire]; // 执行一次 test 方法[timer fire]; // 执行一次 test 方法[timer fire]; // 执行一次 test 方法[timer fire]; // 执行一次 test 方法
–思路1:
–1> 通过 UIPageControl 获取当前页数, 并让页数+1 –2> 根据加1以后的页数乘以每页的宽度(每张图片宽度)计算出contentOffset.x 的偏移值 –3> 手动设置偏移值, 实现滚动 (通过动画方式设置).
切换下一张图片的方法
在这个方法当中, 根据当前的页数, 来计算当前应该设置的偏移量contentOffset的值。- (void)nextImage { // 获取当前的页数 NSInteger page = self.pageControl.currentPage; if (page == self.pageControl.numberOfPages - 1) {page = 0; } else {page++; } // 根据当前是第几页, 计算出偏移量contentOffset的值 CGFloat x = self.scrollView.frame.size.width * page; // 通过代码设置 contentOffset 偏移, 实现自动滚动 // 非动画方式 //self.scrollView.contentOffset = CGPointMake(x, 0); // 动画方式 [self.scrollView setContentOffset:CGPointMake(x, 0) animated:YES]; }
————————– 下面这种思路不好, 有时候有 bug —————————–
当手动拖拽滚动的时候, 此时 contentOffset.x 可能并不是一个完整的宽度, 所以会造成最终计算出来的 contentOffset.x 不是一个完整页的宽度
//直接获取现有的 offset.x 然后加上一个图片的宽度 CGFloat offsetX = self.scrollView.contentOffset.x;offsetX += self.scrollView.frame.size.width;if (offsetX >= self.scrollView.contentSize.width) {offsetX = 0;}//self.scrollView.contentOffset = CGPointMake(offsetX, 0);[self.scrollView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
–Bug: 当拖拽UIScrollView的时候, 保持一段时间不松手的时候, 一旦松手UIScrollView会连续滚动多次。
–解决思路:在即将拖拽的时候, 停止计时器, 拖拽完毕后再打开一个计时器。
停止计时器:调用 NSTimer 对象的 invalidate 方法(当某个计时器被停止以后, 就无法再重用了, 下次必须再重新创建一个新的计时器)。 [self.timer invalidate];
// 在即将拖拽之前 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { // 停止计时器 [self.timer invalidate]; self.timer = nil; } // 在拖拽完毕后再启动计时器 -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { // 重新创建一个计时器对象self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];// 获取当前线程处理事件的消息循环NSRunLoop *runLoop = [NSRunLoop currentRunLoop];// 设置timer的优先级[runLoop addTimer:timer forMode:NSRunLoopCommonModes]; }
Bug:当单击(拖拽)界面上的某个其他控件的时候, UIScrollView停止滚动的问题。
•产生 Bug 的原因: –当前处理UI界面的只有一个线程, 当这个线程处理UI的拖动事件的时候就没有能力再去处理滚动操作了 –注意: 处理UI界面的的只能是一个线程。所以, 处理UIScrollView的滚动和其他控件的拖拽, 只能用同一个线程。如果多个线程都可以操作 UI 那么就会造成混乱的问题 •解决思路: 提高处理滚动的timer的优先级。 •注意: 所有控件的默认优先级都是NSRunLoopCommonModes ,但是网络和计时器对象默认的优先级要比控件的优先级低是 NSDefaultRunLoopMode , 所以这里要把计时器的优先级调整为与控件一样的优先级NSRunLoopCommonModes。
// 获取当前线程处理事件的消息循环NSRunLoop *runLoop = [NSRunLoop currentRunLoop];// 设置timer的优先级[runLoop addTimer:timer forMode:NSRunLoopCommonModes];// 2. 在scrollViewDidEndDragging:中重新创建timer 对象后再修改一次优先级-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { // 重新创建一个计时器对象self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];// 获取当前线程处理事件的消息循环NSRunLoop *runLoop = [NSRunLoop currentRunLoop];// 设置timer的优先级[runLoop addTimer:timer forMode:NSRunLoopCommonModes]; }