闲来无事,小结一下这个无限循环自动滚动视图,忘大神多多提取宝贵意见,相互交流,如有错误不吝赐教。
当我们进行软件开发的时候滚动视图是经常用到的一个UI控件,商城类项目用的是比较多的。下面小弟介绍一下实现流程。
1.将定时器,滚动视图和页码控制器写成一个属性。
.h文件如下(将Scroll滚动视图封装成一个View方便复用)
2.创建滚动视图和页码控制器并且初始化数据,添加定时器
self.titleArr = @[@"********4*********",@"********1*********",@"********2*********",@"********3*********",@"********4*********",@"********1*********"];
//设置按页滚动
self.scrollV.pagingEnabled = YES;
//设置是否显示水平滑动条
self.scrollV.showsHorizontalScrollIndicator = NO;
//设置是否边界反弹
self.scrollV.bounces=NO;
//在此添加代码 设置控件的属性值 backgroundColor
for(inti =0; i
UILabel * label = [[UILabel alloc]initWithFrame:CGRectZero];
label.text=self.titleArr[i];
label.tag=10+ i;
label.textColor = [UIColor redColor];
[self.scrollVaddSubview:label];
}
//设置页面
self.pageC = [[UIPageControl alloc]initWithFrame:CGRectZero];
self.pageC.backgroundColor = [UIColor clearColor];
//设置页码数
self.pageC.numberOfPages = self.titleArr.count;
//设置选中页码的颜色
self.pageC.currentPageIndicatorTintColor = [UIColor brownColor];
//设置未选中的页码颜色
self.pageC.pageIndicatorTintColor = [UIColor grayColor];
//设置当前选中页
self.pageC.currentPage = 0;
//核心方法
[self.pageC addTarget:self action:@selector(pageAction:) forControlEvents:UIControlEventValueChanged];
//自定义一个定时器方法
[self addTimer];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
3.在-(void)layoutSubviews方法中设置scrollView里子控件尺寸和ScrollView的偏移量
-(void)layoutSubviews {
//一定要调用父类的layoutSubviews方法
[super layoutSubviews];
//设置子控件的Frame
for(UIView* viewinself.scrollV.subviews) {
if ([view isKindOfClass:[UILabel class]]) {
UILabel* lab = (UILabel* )view;
lab.frame = CGRectMake(0, self.scrollV.frame.size.height * (lab.tag - 10), self.scrollV.frame.size.width, self.scrollV.frame.size.height);
}
}
//设置滚动量
self.scrollV.contentSize = CGSizeMake(0, self.scrollV.frame.size.height * self.titleArr.count);
//设置偏移量
self.scrollV.contentOffset = CGPointMake(0,self.scrollV.frame.size.height);
//XIB里自定义View必须设置成自动布局,不然Button的Frame不能成功赋值
}
4.添加ScrollView的代理方法(别忘了遵守协议)
//减速停止时触发
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{
//当图片在第一张时
if(scrollView.contentOffset.y==0) {
// 用户滑动到1号位置,此时必须跳转到倒二的位置
[scrollViewsetContentOffset:CGPointMake(0, self.scrollV.frame.size.height * self.titleArr.count - 2) animated:YES];
}
//当图片在倒数第一张时
else if (scrollView.contentOffset.y == scrollView.contentSize.height - self.scrollV.frame.size.height) {
//把倒数第一张位置换成第二张图片
[scrollViewsetContentOffset:CGPointMake(0, self.scrollV.frame.size.height) animated:YES];
}
}
//开始拖拽的时候调用
- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView{
//关闭定时器(注意,定时器一旦被关闭,无法在开启)
[self removeTimer];
}
//拖拽结束后
- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate{
//开启定时器
[self addTimer];
}
5.定时器添加和移除方法(之所以会频繁的添加和移除是为了在手动拖拽的时候定时器控制的滚动和手动滚动冲突,当然代码中我用了两种方法去解决冲突问题,大家可以选其中一种 添加[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; 或者是根据ScrollView的代理方法,删除和重新添加定时器)
//开启定时器
- (void)addTimer{
//设置定时器
self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(change:) userInfo:nil repeats:YES];
}
//关闭定时器
- (void)removeTimer{
if(_timer) {
if([self.timerisValid]) {
[self.timerinvalidate];
_timer=nil;
}
}
}
6.定时器执行方法和转换页面的方法
//定时器执行方法
- (void)change:(NSTimer*)time{
if (self.pageC.currentPage == self.pageC.numberOfPages - 2) {
self.pageC.currentPage=1;
}else if (self.pageC.currentPage < self.pageC.numberOfPages - 2) {
self.pageC.currentPage++;
}
[self.scrollV setContentOffset:CGPointMake(0, (self.pageC.currentPage + 1) * self.scrollV.frame.size.height) animated:NO];
}
//点击页码,换页的方法
- (void)pageAction:(UIPageControl*)page{
[self.scrollV setContentOffset:CGPointMake(0, self.scrollV.frame.size.height * (self.pageC.currentPage + 1)) animated:YES];
}
其中,定时器执行的方法中做了两重判断,而且细心的同仁也能发现数组的数据排列也有一定的问题:
难道数组不应该按顺序来排列么?
是的,数组是应该按照顺序排列的应该是@[@"********1*********",@"********2*********",@"********3*********",@"********4*********"];
这部分转换的原因就是当滚动视图滚动到最后一页的时候如果控制它的下次滚动设置成第一页的话会有一个Bug,跳转到的时候会闪顿,反过来,如果手动从第一页往前翻应该滚动的第四页,但是会出现相同的情况(由于功能实现了,又不是用图片做的,我就没再去做视频展示,见谅)有兴趣的朋友可以去试一下。这样做肯定是不合理的。所以用到了处理数组将数组变成@[@"********4*********",@"********1*********",@"********2*********",@"********3*********",@"********4*********",@"********1*********"];这种样式的 ,最后一个加在最前边,最前边的加在数组的最后边,这样一来数组中数据的数量比之前的原始数组多了两个数据。接下来解释下边这两部分代码:
定时器控制页面的判断语句:
if (self.pageC.currentPage == self.pageC.numberOfPages - 2) {
self.pageC.currentPage=1;
}else if (self.pageC.currentPage < self.pageC.numberOfPages - 2) {
self.pageC.currentPage++;
}
if语句先判断当前的页码是不是需要滚动的内容的最后一条数据,如果是最后一条数据(也就是转换后数组的第五个条)就设置当前页面是第二条(self.pageC.currentPage=1按顺序是第二条),此时第二条是数组中的第二项。定时器先判断当前页面数,通过比较后如果是应该显示的最后一条数据,那么就设置这次滚动的从变换数组的第二项开始,也就是应该显示的第一条数据。同样的道理下边这个代理方法也在处理同样的逻辑。
手动滚动ScrollView的代理方法
if(scrollView.contentOffset.y==0) {
// 用户滑动到1号位置,此时必须跳转到倒二的位置
[scrollViewsetContentOffset:CGPointMake(0, self.scrollV.frame.size.height * self.titleArr.count - 2) animated:YES];
}
//当图片在倒数第一张时
else if (scrollView.contentOffset.y == scrollView.contentSize.height - self.scrollV.frame.size.height) {
//把倒数第一张位置换成第二张图片
[scrollViewsetContentOffset:CGPointMake(0, self.scrollV.frame.size.height) animated:YES];
}
谢谢![email protected]欢迎骚扰!