【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,设置位置、尺寸
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;
没有开启之前,切换两幅图片的时候终止拖曳,会停留在那一刻的显示状态
开启之后效果就像书本翻页一样
5.加入pageControl
pageControl要放在UIScrollView外,而且要比UIScrollView更前,才能正常显示
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 }
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,当拖曳其滚动条时,占用了所有线程刷新资源,定时器就被阻断了
解决:争取主线程资源来刷新(分享资源)
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







浙公网安备 33010602011771号