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

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

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

前言

ios实现无限循环滚动主要有两种办法,都利用了UIScrollView,第一种是创建一个很大的UIScrollView((n+2)*屏幕宽度),把要展示的图片都添加到这个视图上,通过对偏移值的更改达到循环的效果;第二种是创建一个三倍屏幕大小的UIScrollView,只使用三张图片,通过不断更新图片来达到循环的效果。

这两天把这两种方法都写了一次,今天只讲第一种。

效果展示

功能

  • 实现用户左右滑动时可以无限循环滚动
  • 实现图片的自动轮播
  • 用户开始滑动时,自动轮播停止,用户无操作两秒后继续开始自动轮播

分析

本来一开始只打算写左右滑动时的无限滚动的(也没打算加pageControl),但是写着写着就把自动轮播也给写完了。按照我的思路分成四个部分来讲。

  • 用户左右滑动时的无限循环滚动

    原理:要实现左右滑动就是利用UIScrollView的特性,创建一个UIScrollView视图,将视图的可见宽度设为与屏幕同宽,并将视图设置为可分页,图片就可以一页页展示出来。那么该如何实现循环滚动呢?

    当我们需要展示n张图片时,视图的实际宽度要设置为(n+2)*屏幕宽度,因为需要在额外在最前一页放上第一张图片,最后一页放上第一张图片(如图所示)

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

    如图,当显示到要展示的图片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

你可能感兴趣的:(ios开发)