ios之实现自动无限循环滚动视图(1)

ios之实现自动无限循环滚动视图(1)

前言
效果展示
功能
分析
全部代码
前言

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];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
添加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;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
设置定时器

-(void)setupLink{
    //设定一个定时器
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(slideImage)];
    _link.preferredFramesPerSecond = 1;
    [_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
1
2
3
4
5
6
实现用户滑动时,自动轮播停止;用户无操作两秒后,自动轮播继续开始

1.程序启动时,开始启动定时器

-(void)viewDidAppear:(BOOL)animated{
    [self setupLink];
}
1
2
3
2.使用scrollViewWillBeginDragging方法监听scrollView状态,当该方法被调用时,说明用户开始手动拖动scrollView,此时暂停定时器

//用户手动拖动scrollView时,暂停定时器
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
    _link.paused = YES;
}
1
2
3
4
3.当scrollView停止滚动时,设定一个定时器,让它推迟两秒以后再重新启动用于滚动视图的定时器

需要注意的是,用户可能会在两秒以内再次滑动视图,因此必须保证该定时器在最后一次滑动停止时才被启动。使用系统的performSelector方法,可以让该方法在推迟的时间内被多次调用时,只执行最后一次。

    //两秒之后重新启动定时器
    //在调用performSelector前调用这个方法,取消先前的调用请求
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
    [self performSelector:@selector(runLink) withObject:nil afterDelay:2];
1
2
3
4
runLink方法

-(void)runLink{
    _link.paused = NO;
}
1
2
3
全部代码

#import "ViewController.h"

#define KScreenWidth (self.view.frame.size.width)

@interface ViewController ()<UIScrollViewDelegate>

@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
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值