【iOS基础控件 - 7】 广告图片轮播器 <UIScrollView>

A.概念
例子就是桌面的APP列表,当APP数量超过一个屏幕,自动进行分页
 
B.实现思路
1.创建一个UIScrollView,这里设置为宽度跟屏幕相同,高度1/4屏幕高度左右
2.使用代码在UIScrollView中添加ImageView,横向放入多张ImageView
3.设置UIScrollView的contentSize为所有图片的宽度总和
4.要保证UIScrollView的宽度等于一张ImageView的宽度,才能正确分页
 
C.相关属性
设置属性pageEnable = YES,UIScrollView会被分割成多个独立页面,进行分页显示
一般使用UIPageControl增强效果,UIPageControl常见属性:
复制代码
 1     // 总页数
 2     @property(nonatomic) NSInteger numberOfPages;          // default is 0
 3     // 当前页码
 4     @property(nonatomic) NSInteger currentPage;
 5     // 只有一页的时候隐藏页码
 6     @property(nonatomic) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
 7     // 其他页码指示颜色
 8     @property(nonatomic,retain) UIColor *pageIndicatorTintColor;
 9     // 当前页码指示颜色
10     @property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;
复制代码
 
 
D.实现步骤
1. 创建一个UIScrollView,设置位置、尺寸
Image(61)
 
2.用代码加载多张图片
复制代码
 1     CGFloat imageWidth = 300;
 2     CGFloat imageHeight = 130;
 3     CGFloat imageY = 0;
 4    
 5     for (int i=0; i<5; i++) {
 6         CGFloat imageX = i * imageWidth;
 7         UIImageView *currentImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d", i+1]]];
 8         currentImageView.frame = CGRectMake(imageX, imageY, imageWidth, imageHeight);
 9        
10         [self.scrollView addSubview:currentImageView];
11     }
复制代码
 
3.设置contentSize
1     // 设置可以拖曳的范围,只允许横向拖曳,而且范围是所有的图片宽度总和
2     self.scrollView.contentSize = CGSizeMake(5 * imageWidth, 0);
 
4.开启 pageEnable = YES
     每次拖曳至少滑动1个UIScrollView宽度单位,设置UIScrollView的宽度为图片的宽度之后,刚好翻过一页。
1     // 开启翻页模式,每次拖曳都会滑动一个UIScrollView宽度单位
2     self.scrollView.pagingEnabled = YES;
 
没有开启之前,切换两幅图片的时候终止拖曳,会停留在那一刻的显示状态
Image(62)
 
开启之后效果就像书本翻页一样
Image(63)
 
 
5.加入pageControl
pageControl要放在UIScrollView外,而且要比UIScrollView更前,才能正常显示
Image(64)
 
 
6.使用代码设置pageControl
pageControl属性:
复制代码
 1     // 总页数
 2     @property(nonatomic) NSInteger numberOfPages;          // default is 0
 3     // 当前页码
 4     @property(nonatomic) NSInteger currentPage;
 5     // 只有一页的时候隐藏页码
 6     @property(nonatomic) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
 7     // 其他页码指示颜色
 8     @property(nonatomic,retain) UIColor *pageIndicatorTintColor;
 9     // 当前页码指示颜色
10     @property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;
复制代码
 
(1)要手动设置pageControl,它才能正常工作
1     // 设置pageControl
2     self.pageControl.numberOfPages = 5;
3     self.pageControl.pageIndicatorTintColor = [UIColor blackColor];
4    
5     //设置delegate
6     self.scrollView.delegate = self;
 
(2)控制器遵守UIScrollViewDelegate协议,在 scrollViewDidScroll中动态设置当前页码
复制代码
1 /** 当scrollView滚动的时候调用 */
2 - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
3     CGFloat scrollWidth = scrollView.frame.size.width;
4    
5     // 当一副图片拖曳超过一半的时候就重新计算页码
6     int page = (scrollView.contentOffset.x + scrollWidth * 0.5) / scrollWidth;
7    
8     self.pageControl.currentPage = page;
9 }
复制代码
 
Image(65)
 
 
7.使用定时器NSTimer自动换页
(1)添加定时器
1     // 创建定时器
2     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
 
(2)创建定时器调用的方法
复制代码
 1 - (void) nextImage {
 2     // 1.增加pageControl的页码,这里不能直接操作currentPage,因为这样会和scrollViewDidScroll的页码计算冲突,应该是滚动画面,触发scrollViewDidScroll进行页码转换
 3     int pageNo = 0;
 4     if (self.pageControl.currentPage == (IMAGE_COUNT - 1)) {
 5         pageNo = 0;
 6     }
 7     else {
 8         pageNo = self.pageControl.currentPage + 1;
 9     }
10  
11     // 2.计算scrollView的滑动位置
12     CGFloat offsetX = pageNo * self.scrollView.frame.size.width;
13     CGPoint offset = CGPointMake(offsetX, 0);
14    
15     // 移动一页,带动画效果
16     [self.scrollView setContentOffset:offset  animated:YES];
17 }
复制代码
 
(3)定时器的弱点,在单线程运行时,得不到线程资源的时候,定时器定制运行,事件累积,得到资源之后才一起运行,这里有两种情况:
 
a.手动拖曳阻止了定时器
     解决:销毁定时器,确保资源之后再创建一个
复制代码
 1 // 开始手动拖曳的时候,销毁定时器
 2 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 3     [self.timer invalidate]; // 调用了invalidate之后再不可用了
 4     self.timer = nil;
 5 }
 6 
 7 // 结束手动拖曳,重新定义定时器
 8 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
 9     [self addTimer];
10 }
11 
12 // 添加定时器
13 - (void) addTimer {
14     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
15 }
复制代码
 
b.外部可刷新的控件抢占了所有线程资源
如下图中,添加了一个TextView,当拖曳其滚动条时,占用了所有线程刷新资源,定时器就被阻断了
Image(66)
 
解决:争取主线程资源来刷新(分享资源)
复制代码
1 // 添加定时器
2 - (void) addTimer {
3     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
4    
5     // 获得主线程资源,防止另外的如可滚动控件的资源全占用
6     [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
7 }
复制代码
 
 
E.滚动页的优化
1.只使用3个ImageView加载图片,动态加载图片
2.无限滚动
 
 
F.主要代码:
复制代码
  1 //
  2 //  ViewController.m
  3 //  ScrollViewPage
  4 //
  5 //  Created by hellovoidworld on 14/11/28.
  6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 
 11 #define IMAGE_COUNT 5
 12 
 13 @interface ViewController () <UIScrollViewDelegate>
 14 @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; // 滚动控件
 15 @property (weak, nonatomic) IBOutlet UIPageControl *pageControl; // 页码控件
 16 
 17 @property(nonatomic, strong) NSTimer *timer; // 定时器
 18 
 19 @end
 20 
 21 @implementation ViewController
 22 
 23 - (void)viewDidLoad {
 24     [super viewDidLoad];
 25     // Do any additional setup after loading the view, typically from a nib.
 26    
 27 
 28    
 29     CGFloat imageWidth = 300;
 30     CGFloat imageHeight = 130;
 31     CGFloat imageY = 0;
 32    
 33     for (int i=0; i<IMAGE_COUNT; i++) {
 34         CGFloat imageX = i * imageWidth;
 35         UIImageView *currentImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d", i+1]]];
 36         currentImageView.frame = CGRectMake(imageX, imageY, imageWidth, imageHeight);
 37        
 38         [self.scrollView addSubview:currentImageView];
 39     }
 40    
 41     // 设置可以拖曳的范围,只允许横向拖曳,而且范围是所有的图片宽度总和
 42     self.scrollView.contentSize = CGSizeMake(IMAGE_COUNT * imageWidth, 0);
 43    
 44     // 开启翻页模式,每次拖曳都会滑动一个UIScrollView宽度单位
 45     self.scrollView.pagingEnabled = YES;
 46    
 47     // 设置pageControl
 48     self.pageControl.numberOfPages = 5;
 49     self.pageControl.pageIndicatorTintColor = [UIColor blackColor];
 50     self.pageControl.currentPageIndicatorTintColor = [UIColor redColor];
 51    
 52     // 设置delegate
 53     self.scrollView.delegate = self;
 54    
 55     // 创建定时器
 56     [self addTimer];
 57 }
 58 
 59 - (void)didReceiveMemoryWarning {
 60     [super didReceiveMemoryWarning];
 61     // Dispose of any resources that can be recreated.
 62 }
 63 
 64 
 65 /** 当scrollView滚动的时候调用 */
 66 - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
 67     CGFloat scrollWidth = scrollView.frame.size.width;
 68    
 69     // 当一副图片拖曳超过一半的时候就重新计算页码
 70     int page = (scrollView.contentOffset.x + scrollWidth * 0.5) / scrollWidth;
 71    
 72     self.pageControl.currentPage = page;
 73 }
 74 
 75 - (void) nextImage {
 76     // 1.增加pageControl的页码,这里不能直接操作currentPage,因为这样会和scrollViewDidScroll的页码计算冲突,应该是滚动画面,触发scrollViewDidScroll进行页码转换
 77     int pageNo = 0;
 78     if (self.pageControl.currentPage == (IMAGE_COUNT - 1)) {
 79         pageNo = 0;
 80     }
 81     else {
 82         pageNo = self.pageControl.currentPage + 1;
 83     }
 84 
 85     // 2.计算scrollView的滑动位置
 86     CGFloat offsetX = pageNo * self.scrollView.frame.size.width;
 87     CGPoint offset = CGPointMake(offsetX, 0);
 88    
 89     // 移动一页,带动画效果
 90     [self.scrollView setContentOffset:offset  animated:YES];
 91 }
 92 
 93 // 开始手动拖曳的时候,销毁定时器
 94 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 95     [self.timer invalidate]; // 调用了invalidate之后再不可用了
 96     self.timer = nil;
 97 }
 98 
 99 // 结束手动拖曳,重新定义定时器
100 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
101     [self addTimer];
102 }
103 
104 // 添加定时器
105 - (void) addTimer {
106     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
107    
108     // 获得主线程资源,防止另外的如可滚动控件的资源全占用
109     [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
110 }
111 
112 @end
复制代码
A.概念
例子就是桌面的APP列表,当APP数量超过一个屏幕,自动进行分页
 
B.实现思路
1.创建一个UIScrollView,这里设置为宽度跟屏幕相同,高度1/4屏幕高度左右
2.使用代码在UIScrollView中添加ImageView,横向放入多张ImageView
3.设置UIScrollView的contentSize为所有图片的宽度总和
4.要保证UIScrollView的宽度等于一张ImageView的宽度,才能正确分页
 
C.相关属性
设置属性pageEnable = YES,UIScrollView会被分割成多个独立页面,进行分页显示
一般使用UIPageControl增强效果,UIPageControl常见属性:
复制代码
 1     // 总页数
 2     @property(nonatomic) NSInteger numberOfPages;          // default is 0
 3     // 当前页码
 4     @property(nonatomic) NSInteger currentPage;
 5     // 只有一页的时候隐藏页码
 6     @property(nonatomic) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
 7     // 其他页码指示颜色
 8     @property(nonatomic,retain) UIColor *pageIndicatorTintColor;
 9     // 当前页码指示颜色
10     @property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;
复制代码
 
 
D.实现步骤
1. 创建一个UIScrollView,设置位置、尺寸
Image(61)
 
2.用代码加载多张图片
复制代码
 1     CGFloat imageWidth = 300;
 2     CGFloat imageHeight = 130;
 3     CGFloat imageY = 0;
 4    
 5     for (int i=0; i<5; i++) {
 6         CGFloat imageX = i * imageWidth;
 7         UIImageView *currentImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d", i+1]]];
 8         currentImageView.frame = CGRectMake(imageX, imageY, imageWidth, imageHeight);
 9        
10         [self.scrollView addSubview:currentImageView];
11     }
复制代码
 
3.设置contentSize
1     // 设置可以拖曳的范围,只允许横向拖曳,而且范围是所有的图片宽度总和
2     self.scrollView.contentSize = CGSizeMake(5 * imageWidth, 0);
 
4.开启 pageEnable = YES
     每次拖曳至少滑动1个UIScrollView宽度单位,设置UIScrollView的宽度为图片的宽度之后,刚好翻过一页。
1     // 开启翻页模式,每次拖曳都会滑动一个UIScrollView宽度单位
2     self.scrollView.pagingEnabled = YES;
 
没有开启之前,切换两幅图片的时候终止拖曳,会停留在那一刻的显示状态
Image(62)
 
开启之后效果就像书本翻页一样
Image(63)
 
 
5.加入pageControl
pageControl要放在UIScrollView外,而且要比UIScrollView更前,才能正常显示
Image(64)
 
 
6.使用代码设置pageControl
pageControl属性:
复制代码
 1     // 总页数
 2     @property(nonatomic) NSInteger numberOfPages;          // default is 0
 3     // 当前页码
 4     @property(nonatomic) NSInteger currentPage;
 5     // 只有一页的时候隐藏页码
 6     @property(nonatomic) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO
 7     // 其他页码指示颜色
 8     @property(nonatomic,retain) UIColor *pageIndicatorTintColor;
 9     // 当前页码指示颜色
10     @property(nonatomic,retain) UIColor *currentPageIndicatorTintColor;
复制代码
 
(1)要手动设置pageControl,它才能正常工作
1     // 设置pageControl
2     self.pageControl.numberOfPages = 5;
3     self.pageControl.pageIndicatorTintColor = [UIColor blackColor];
4    
5     //设置delegate
6     self.scrollView.delegate = self;
 
(2)控制器遵守UIScrollViewDelegate协议,在 scrollViewDidScroll中动态设置当前页码
复制代码
1 /** 当scrollView滚动的时候调用 */
2 - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
3     CGFloat scrollWidth = scrollView.frame.size.width;
4    
5     // 当一副图片拖曳超过一半的时候就重新计算页码
6     int page = (scrollView.contentOffset.x + scrollWidth * 0.5) / scrollWidth;
7    
8     self.pageControl.currentPage = page;
9 }
复制代码
 
Image(65)
 
 
7.使用定时器NSTimer自动换页
(1)添加定时器
1     // 创建定时器
2     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
 
(2)创建定时器调用的方法
复制代码
 1 - (void) nextImage {
 2     // 1.增加pageControl的页码,这里不能直接操作currentPage,因为这样会和scrollViewDidScroll的页码计算冲突,应该是滚动画面,触发scrollViewDidScroll进行页码转换
 3     int pageNo = 0;
 4     if (self.pageControl.currentPage == (IMAGE_COUNT - 1)) {
 5         pageNo = 0;
 6     }
 7     else {
 8         pageNo = self.pageControl.currentPage + 1;
 9     }
10  
11     // 2.计算scrollView的滑动位置
12     CGFloat offsetX = pageNo * self.scrollView.frame.size.width;
13     CGPoint offset = CGPointMake(offsetX, 0);
14    
15     // 移动一页,带动画效果
16     [self.scrollView setContentOffset:offset  animated:YES];
17 }
复制代码
 
(3)定时器的弱点,在单线程运行时,得不到线程资源的时候,定时器定制运行,事件累积,得到资源之后才一起运行,这里有两种情况:
 
a.手动拖曳阻止了定时器
     解决:销毁定时器,确保资源之后再创建一个
复制代码
 1 // 开始手动拖曳的时候,销毁定时器
 2 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 3     [self.timer invalidate]; // 调用了invalidate之后再不可用了
 4     self.timer = nil;
 5 }
 6 
 7 // 结束手动拖曳,重新定义定时器
 8 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
 9     [self addTimer];
10 }
11 
12 // 添加定时器
13 - (void) addTimer {
14     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
15 }
复制代码
 
b.外部可刷新的控件抢占了所有线程资源
如下图中,添加了一个TextView,当拖曳其滚动条时,占用了所有线程刷新资源,定时器就被阻断了
Image(66)
 
解决:争取主线程资源来刷新(分享资源)
复制代码
1 // 添加定时器
2 - (void) addTimer {
3     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
4    
5     // 获得主线程资源,防止另外的如可滚动控件的资源全占用
6     [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
7 }
复制代码
 
 
E.滚动页的优化
1.只使用3个ImageView加载图片,动态加载图片
2.无限滚动
 
 
F.主要代码:
复制代码
  1 //
  2 //  ViewController.m
  3 //  ScrollViewPage
  4 //
  5 //  Created by hellovoidworld on 14/11/28.
  6 //  Copyright (c) 2014年 hellovoidworld. All rights reserved.
  7 //
  8 
  9 #import "ViewController.h"
 10 
 11 #define IMAGE_COUNT 5
 12 
 13 @interface ViewController () <UIScrollViewDelegate>
 14 @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; // 滚动控件
 15 @property (weak, nonatomic) IBOutlet UIPageControl *pageControl; // 页码控件
 16 
 17 @property(nonatomic, strong) NSTimer *timer; // 定时器
 18 
 19 @end
 20 
 21 @implementation ViewController
 22 
 23 - (void)viewDidLoad {
 24     [super viewDidLoad];
 25     // Do any additional setup after loading the view, typically from a nib.
 26    
 27 
 28    
 29     CGFloat imageWidth = 300;
 30     CGFloat imageHeight = 130;
 31     CGFloat imageY = 0;
 32    
 33     for (int i=0; i<IMAGE_COUNT; i++) {
 34         CGFloat imageX = i * imageWidth;
 35         UIImageView *currentImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"img_%02d", i+1]]];
 36         currentImageView.frame = CGRectMake(imageX, imageY, imageWidth, imageHeight);
 37        
 38         [self.scrollView addSubview:currentImageView];
 39     }
 40    
 41     // 设置可以拖曳的范围,只允许横向拖曳,而且范围是所有的图片宽度总和
 42     self.scrollView.contentSize = CGSizeMake(IMAGE_COUNT * imageWidth, 0);
 43    
 44     // 开启翻页模式,每次拖曳都会滑动一个UIScrollView宽度单位
 45     self.scrollView.pagingEnabled = YES;
 46    
 47     // 设置pageControl
 48     self.pageControl.numberOfPages = 5;
 49     self.pageControl.pageIndicatorTintColor = [UIColor blackColor];
 50     self.pageControl.currentPageIndicatorTintColor = [UIColor redColor];
 51    
 52     // 设置delegate
 53     self.scrollView.delegate = self;
 54    
 55     // 创建定时器
 56     [self addTimer];
 57 }
 58 
 59 - (void)didReceiveMemoryWarning {
 60     [super didReceiveMemoryWarning];
 61     // Dispose of any resources that can be recreated.
 62 }
 63 
 64 
 65 /** 当scrollView滚动的时候调用 */
 66 - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
 67     CGFloat scrollWidth = scrollView.frame.size.width;
 68    
 69     // 当一副图片拖曳超过一半的时候就重新计算页码
 70     int page = (scrollView.contentOffset.x + scrollWidth * 0.5) / scrollWidth;
 71    
 72     self.pageControl.currentPage = page;
 73 }
 74 
 75 - (void) nextImage {
 76     // 1.增加pageControl的页码,这里不能直接操作currentPage,因为这样会和scrollViewDidScroll的页码计算冲突,应该是滚动画面,触发scrollViewDidScroll进行页码转换
 77     int pageNo = 0;
 78     if (self.pageControl.currentPage == (IMAGE_COUNT - 1)) {
 79         pageNo = 0;
 80     }
 81     else {
 82         pageNo = self.pageControl.currentPage + 1;
 83     }
 84 
 85     // 2.计算scrollView的滑动位置
 86     CGFloat offsetX = pageNo * self.scrollView.frame.size.width;
 87     CGPoint offset = CGPointMake(offsetX, 0);
 88    
 89     // 移动一页,带动画效果
 90     [self.scrollView setContentOffset:offset  animated:YES];
 91 }
 92 
 93 // 开始手动拖曳的时候,销毁定时器
 94 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
 95     [self.timer invalidate]; // 调用了invalidate之后再不可用了
 96     self.timer = nil;
 97 }
 98 
 99 // 结束手动拖曳,重新定义定时器
100 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
101     [self addTimer];
102 }
103 
104 // 添加定时器
105 - (void) addTimer {
106     self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(nextImage) userInfo:nil repeats:YES];
107    
108     // 获得主线程资源,防止另外的如可滚动控件的资源全占用
109     [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
110 }
111 
112 @end
复制代码
posted @ 2015-01-20 10:19  kengsir  阅读(345)  评论(0编辑  收藏  举报