在做项目是有时候会遇到设置自动滚动图片,UIScrollView是一个挺有意思东西,所以做了下总结
DEMO:
.h
#import <UIKit/UIKit.h> @interface ImagePlayView : UIView<UIScrollViewDelegate> @property (nonatomic, strong) UIScrollView * scroll; @property (nonatomic, strong) UIPageControl * play; @property (nonatomic, strong) NSTimer * timer; @end
.m
#import "ImagePlayView.h"
// 定义图片的总数
#define ImageCount 3;
@implementation ImagePlayView
- (id) initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
// 创建一个UIscrollView组件,作为滚动组件的头视图
CGRect headScroll = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
_scroll = [[UIScrollView alloc] initWithFrame:headScroll];
// 取消水平滚动条
_scroll.showsHorizontalScrollIndicator = NO;
// 取消弹性设置
_scroll.bounces = NO;
// 设置分页
_scroll.pagingEnabled = YES;
[self addSubview: _scroll];
// 循环创建多个UIImageView
for (int i = 0; i < ImageCount ; i ++)
{
UIImageView * imageV = [[UIImageView alloc] initWithFrame:CGRectMake(i * self.frame.size.width, 0, self.frame.size.width, self.frame.size.height)];
imageV.image = [UIImage imageNamed:[NSString stringWithFormat:@"banner-%d",i + 1]];
[_scroll addSubview: imageV];
}
_scroll.contentSize = CGSizeMake(3 * self.frame.size.width, 0);
_scroll.delegate = self;
// 设置分页指示器
_play = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width/3, 20)];
// 设置分页器的位置
_play.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/1.2);
// 设置其它页指示器圆点的颜色
_play.pageIndicatorTintColor = [UIColor grayColor];
// 设置当前页指示器圆点的颜色
_play.currentPageIndicatorTintColor = [UIColor grayColor];
// 设置分页器的页数
_play.numberOfPages = ImageCount;
// 设置当前是第几页
_play.currentPageIndicatorTintColor = 0;
[self addSubview:_play];
//设置计时器
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(time)
userInfo:nil repeats:YES];
// 先获取当前的消息循环,利用消息循环设置计时器对象的优先级和控件的优先级相同
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:self.timer forMode:NSRunLoopCommonModes];
}
return self;
}
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
// 解决第一个Bug:按住滚动内容拖拽或不松手,一旦松手就会滚动好多次。
// 解决方法当开始拖动时令计时器失效。当拖动结束后再新建一个计时器
[self.timer invalidate];
// 计时器一旦失效,就不能再使用了
// 所以赋给它一个空指针
self.timer = nil;
}
// 在UIScrollView拖动的过程中会执行这个方法
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// 先获根据内容的偏移位置,获取当前的页数
int page =( scrollView.contentOffset.x+scrollView.frame.size.width*0.5)/ scrollView.frame.size.width;
// 在拖动的过程中把当前的页码告知分页控制器组件
self.play.currentPage = page;
}
// 在拖动结束后会执行这个方法
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
// 当拖动结束后再新建一个计时器, 第一个Bug解除了
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(time)
userInfo:nil
repeats:YES
];
// 解决第二个BUg:当拖动点击别的控件时。
// 将停止滚动,这是由于单线程执行,而计时器对象和网络对象的优先级小于控件的优先级,所以当拖动控件时,就不会再执行NSTimer 计时器对象的操作。
// 解决方法如下:每当新建一个NSTimer计时器,就先获取当前的消息循环,并在消息循环中设置NSTimer的优先级和控件的优先级相同 ,这时 程序会分时间片给优先级相同的对象;
NSRunLoop *runRoop = [NSRunLoop currentRunLoop];
// 获取当前的消息循环
// 利用消息循环为timer对象设置优先级和控件的优先级相同
[runRoop addTimer:self.timer forMode:NSRunLoopCommonModes];
}
// NSTimer处理事件的方法
- (void) time {
// 获取当前的页数
// 0,1,2
NSInteger page = self.play.currentPage; if (page == self.play.numberOfPages-1) { page = 0; }else{ page++; } // 根据当前的页数计算内容偏移量contentOffset的大小 // 通过代码设置contentOffset偏移,实现自动滚动 // 非动画方式 //self.scrollView.contentOffset = CGPointMake(page*self.scrollView.frame.size.width, 0); // 通过动画方式 [self.scroll setContentOffset:CGPointMake(page*self.scroll.frame.size.width, 0) animated:YES]; } @end