ios实现无限循环滚动主要有两种办法,都利用了UIScrollView,第一种是创建一个很大的UIScrollView((n+2)*屏幕宽度),把要展示的图片都添加到这个视图上,通过对偏移值的更改达到循环的效果;第二种是创建一个三倍屏幕大小的UIScrollView,只使用三张图片,通过不断更新图片来达到循环的效果。
这两天把这两种方法都写了一次,今天只讲第一种。
本来一开始只打算写左右滑动时的无限滚动的(也没打算加pageControl),但是写着写着就把自动轮播也给写完了。按照我的思路分成四个部分来讲。
用户左右滑动时的无限循环滚动
原理:要实现左右滑动就是利用UIScrollView的特性,创建一个UIScrollView视图,将视图的可见宽度设为与屏幕同宽,并将视图设置为可分页,图片就可以一页页展示出来。那么该如何实现循环滚动呢?
当我们需要展示n张图片时,视图的实际宽度要设置为(n+2)*屏幕宽度,因为需要在额外在最前一页放上第一张图片,最后一页放上第一张图片(如图所示)
如图,当显示到要展示的图片4,并且要继续向右滑动时,逻辑上来说我们需要回到要展示的图片1,才能继续循环。但为了实现“向右滑动”的效果,需要额外在最后一页放上一张图片1,展示出向右滑的动画,再偷偷将UIScrollView的偏移量调整到要展示的图片1位置(不显示动画),营造出一种“一直在向右滑”的假象。
代码如下:
//当scrollView停止滚动之后调用此方法
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//计算偏移量所对应的页数
int page = scrollView.contentOffset.x/KScreenWidth;
//NSLog(@"%d",page);
if (page == 0) {
//此时应滚到最后一页
//重新设置偏移量
scrollView.contentOffset = CGPointMake(KScreenWidth*4, 0);
//可以用这句代替上一句重新设置偏移量
//可以将animated改成YES体验一下效果
//[scrollView setContentOffset:CGPointMake(KScreenWidth*4, 0) animated:NO];
_pageControl.currentPage = 3;
}else if (page == 5){
//此时应滚到第一页
scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
_pageControl.currentPage = 0;
}else{
_pageControl.currentPage = page-1;
}
//两秒之后重新启动定时器
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
[self performSelector:@selector(runLink) withObject:nil afterDelay:2];
}
添加pageControl
没什么特别要说的,利用(contentOffset.x/屏幕宽度)正好可以计算出当前所在的页数,直接赋值即可。
系统提供的pageControl类比较简单,没有点击小圆点就跳转到相应图片的功能,要实现这个功能还需要自己去写。
添加定时器实现自动轮播
写一个方法通过改变偏移量来实现UIScrollView的自动滚动,并且设定定时器在一定时间内重复调用此方法。
代码如下
-(void)slideImage{
int page = _scrollView.contentOffset.x / KScreenWidth;
if (page == 5) {
//第一张图片实际上已经展示完了
//回到第一页
_scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
//添加动画效果跳转到第二页
[_scrollView setContentOffset:CGPointMake(KScreenWidth*2, 0) animated:YES];
}else{
//使用这个方法没有滑动的效果,跳转起来会很难看
//_scrollView.contentOffset = CGPointMake((page+1)*KScreenWidth, 0);
[_scrollView setContentOffset:CGPointMake((page+1)*KScreenWidth, 0) animated:YES];
}
if (page == 4) {
_pageControl.currentPage = 0;
}else if(page == 5){
_pageControl.currentPage = 1;
}else{
_pageControl.currentPage = page;
}
}
设置定时器
-(void)setupLink{
//设定一个定时器
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(slideImage)];
_link.preferredFramesPerSecond = 1;
[_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
实现用户滑动时,自动轮播停止;用户无操作两秒后,自动轮播继续开始
1.程序启动时,开始启动定时器
-(void)viewDidAppear:(BOOL)animated{
[self setupLink];
}
2.使用scrollViewWillBeginDragging方法监听scrollView状态,当该方法被调用时,说明用户开始手动拖动scrollView,此时暂停定时器
//用户手动拖动scrollView时,暂停定时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
_link.paused = YES;
}
3.当scrollView停止滚动时,设定一个定时器,让它推迟两秒以后再重新启动用于滚动视图的定时器
需要注意的是,用户可能会在两秒以内再次滑动视图,因此必须保证该定时器在最后一次滑动停止时才被启动。使用系统的performSelector方法,可以让该方法在推迟的时间内被多次调用时,只执行最后一次。
//两秒之后重新启动定时器
//在调用performSelector前调用这个方法,取消先前的调用请求
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
[self performSelector:@selector(runLink) withObject:nil afterDelay:2];
runLink方法
-(void)runLink{
_link.paused = NO;
}
#import "ViewController.h"
#define KScreenWidth (self.view.frame.size.width)
@interface ViewController ()
@property(nonatomic,strong)UIScrollView *scrollView;
@property(nonatomic,strong)UIPageControl *pageControl;
@property(nonatomic,strong)CADisplayLink *link;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置scrollView
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 100, KScreenWidth, 300)];
//scrollView的真实大小
_scrollView.contentSize = CGSizeMake(6*KScreenWidth, 300);
//滑动到边缘时的弹簧效果
_scrollView.bounces = NO;
//是否分页显示
_scrollView.pagingEnabled = YES;
//设置背景颜色,便于观察
_scrollView.backgroundColor = [UIColor orangeColor];
//设置代理
_scrollView.delegate = self;
//设置数据
for (int i = 0; i < 6; i ++) {
NSString *imgName;
if (i == 0) {
//第一张 显示最后一张图片
imgName = @"4";
}else if (i == 5){
//最后一张 显示第一张图片
imgName = @"1";
}else{
//其他
imgName = [NSString stringWithFormat:@"%d",i];
}
//显示视图
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(i*KScreenWidth, 0, KScreenWidth, 300)];
imgView.image = [UIImage imageNamed:imgName];
[_scrollView addSubview:imgView];
}
//默认显示ScrollView的第二页,即第一张图片
_scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
//设置小圆点
self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(KScreenWidth/2-20, 350, 20, 20)];
_pageControl.numberOfPages = 4;
_pageControl.currentPage = 0;
_pageControl.pageIndicatorTintColor = [UIColor grayColor];
_pageControl.currentPageIndicatorTintColor = [UIColor orangeColor];
[self.view addSubview:_scrollView];
[self.view addSubview:_pageControl];
}
-(void)viewDidAppear:(BOOL)animated{
[self setupLink];
}
//用户手动拖动scrollView时,暂停计时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
//NSLog(@"here");
_link.paused = YES;
}
//当scrollView停止滚动之后调用,调用此方法
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
//计算偏移量所对应的页数
int page = scrollView.contentOffset.x/KScreenWidth;
//NSLog(@"%d",page);
if (page == 0) {
//此时应滚到最后一页
//重新设置偏移量
scrollView.contentOffset = CGPointMake(KScreenWidth*4, 0);
//[scrollView setContentOffset:CGPointMake(KScreenWidth*4, 0) animated:NO];
_pageControl.currentPage = 3;
}else if (page == 5){
//此时应滚到第一页
scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
_pageControl.currentPage = 0;
}else{
_pageControl.currentPage = page-1;
}
//两秒之后重新启动定时器
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
[self performSelector:@selector(runLink) withObject:nil afterDelay:2];
}
-(void)runLink{
_link.paused = NO;
}
-(void)setupLink{
//设定一个定时器
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(slideImage)];
_link.preferredFramesPerSecond = 1;
[_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
-(void)slideImage{
int page = _scrollView.contentOffset.x / KScreenWidth;
if (page == 5) {
//回到第一页
_scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
//跳转到第二页
[_scrollView setContentOffset:CGPointMake(KScreenWidth*2, 0) animated:YES];
}else{
//_scrollView.contentOffset = CGPointMake((page+1)*KScreenWidth, 0);
[_scrollView setContentOffset:CGPointMake((page+1)*KScreenWidth, 0) animated:YES];
}
if (page == 4) {
_pageControl.currentPage = 0;
}else if(page == 5){
_pageControl.currentPage = 1;
}else{
_pageControl.currentPage = page;
}
// NSLog(@"page:%d",page);
// NSLog(@"currentpage:%ld",_pageControl.currentPage);
}
@end