ios之实现自动无限循环滚动视图(2)(三张图实现)

ios之实现自动无限循环滚动视图(2)(三张图实现)

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

前言

ios实现无限循环滚动的两种方法,昨天已经讲了第一种,第一种方法的弊端是,假如要展示很多张图片(成百上千张),UIScrollView要设置的contentSize值会非常大,同时,假如这些图片都是从网络下载的,要先一次性下载全部的图片明显也不合理。因此一般采用第二种方法,只用三个图片视图用于展示,每次滑动结束后再获取新的图片数据,然后重新展示到视图上。

附:昨天写的第一种方法
ios之实现自动无限循环滚动视图(1)

效果展示

功能

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

分析

其他部分和昨天的差不多,主要是在实现无限循环滚动时有区别。下面讲解一下原理。

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

UIScrollView的真实范围只有三个屏幕宽度,分成三个图片视图,每次滑动结束时,都要重新设置三个视图的图片(setImage)。设有一个图片数组imagesArray,每次只需要三张图片,即要展示的图片(i)、它前一张图片(i-1)、它后一张图片(i+1);当要展示的图片是第一张图片时,它前一张图片就是图片数组的最后一张图片imagesArray[lastObject];当要展示的图片是最后一张图片时,它后一张图片就是图片数组的第一张图片imagesArray[firstObject]。

因此需要一个变量来保存当前所展示的图片是第几张,并且实现一个方法,输入要展示的图片序号即可返回包含其左右图片的数组

方法的代码

//根据传来的值返回其左右的图像
-(NSMutableArray *)getImgToShowByIndex:(int )index{
    NSMutableArray *imgArray = [NSMutableArray array]; 
    
    if(index == 0){
        //第一张 4 0 1
        [imgArray addObject:[_imagesArray objectAtIndex:4]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:index +1]];
        
    }else if(index == 4){
        //最后一张 3 4 0
        [imgArray addObject:[_imagesArray objectAtIndex:index - 1]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:0]];
        
    }else{
        [imgArray addObject:[_imagesArray objectAtIndex:index -1]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:index +1]];
    }
    
    return imgArray;
}

在滑动结束后,通过偏移量计算出移动的方向,然后计算出要展示的图片序号,调用方法得到用于展示的图片数组即可。需要注意,在滑动结束后仍需要偷偷将偏移量调整回中间视图的位置(不添加动画)。

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    //通过偏移量计算方向 等于零->向左  等于2->向右
    //NSLog(@"%f",scrollView.contentOffset.x);
    int direction = scrollView.contentOffset.x/KScreenWidth;
    if (direction == 0) {
        //向左
        if (_index == 0) {
            _index = 4;
        }else{
            _index --;
        }
    }else{
        //向右
        if (_index == 4) {
            _index = 0;
        }else{
            _index ++;
        }
    }
    _pageControl.currentPage = _index;
    NSArray *array = [NSArray arrayWithArray:[self getImgToShowByIndex:_index]];
    [_leftView setImage: [array objectAtIndex:0]];
    [_middleView setImage:[array objectAtIndex:1]];
    [_rightView setImage:[array objectAtIndex:2]];
    //将偏移值移回中间
    scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
    
    //两秒之后重新启动定时器
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
    [self performSelector:@selector(runLink) withObject:nil afterDelay:2];
}

自动轮播这个部分,由于添加了pageControl,但是循环的实现主要靠数据的更新,而不是偏移量的改变。如果添加了动画会造成pageControl和图片变化不符的情况,没想好解决方法,就不添加动画效果,让它跳得丑一些……

在判断方向这一块没做好,出现了只要偏移量一发生视图一定会变化的情况。而实际情况是用户可能只拖了一点点之后不想滑了就放手了,此时不应该执行变化

总结

这次的代码写得不是很好,有些部分感觉有点傻瓜。主要是想自己写一写感受一下原理,没去看其他人是怎么实现的,也没有进行什么优化。一开始想分享代码方便些就全部写在ViewController里了,为了快点做出效果数据也是死的,后来觉得这样非常不好,写过就过了,以后要用到还得再重新写。于是决定以后还是按照标准的方式,该封装就封装,便于以后复用,绝不重复写无意义的东西。

所以这个功能会用自定义类的方式再写一次,最近正在学着用GitHub,以后有意义一些的项目会直接分享到GitHub上。这个demo就到此为止了,存在的问题重写时会解决。

全部代码

#import "ViewController.h"

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

@interface ViewController ()

@property(nonatomic,strong) UIScrollView *scrollView;
@property(nonatomic,strong) UIImageView *leftView;
@property(nonatomic,strong) UIImageView *middleView;
@property(nonatomic,strong) UIImageView *rightView;

@property(nonatomic,strong) UIPageControl *pageControl;

@property(nonatomic,strong) CADisplayLink *link;

//图片数组
@property(nonatomic,strong) NSMutableArray *imagesArray;
@property(nonatomic,assign) int index;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.imagesArray = [NSMutableArray array];
    //设置数据
    for (int i = 0; i < 5; i ++) {
        [_imagesArray addObject: [UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]]];
    }
    self.index = 0;
    
    
    
    /*
         只设置三张图片,每次滑动时重新加载数据(滑动完毕后将scrollView的偏移值移回中间位置
             1 2 3 -> 滑动完毕 2 3 4
     */
   
    //设置scrollView
    self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 100, KScreenWidth, 300)];
    //scrollView的真实大小(三个屏幕即可
    _scrollView.contentSize = CGSizeMake(3*KScreenWidth, 300);
    //滑动到边缘时的弹簧效果
    _scrollView.bounces = NO;
    //是否分页显示
    _scrollView.pagingEnabled = YES;
    //设置背景颜色,便于观察
    _scrollView.backgroundColor = [UIColor orangeColor];
    //设置代理
    _scrollView.delegate = self;
    _scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
    
    //设置初始化页面
    self.leftView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, KScreenWidth, 300)];
    [self.leftView setImage:[_imagesArray objectAtIndex:4]];
    [_scrollView addSubview:_leftView];
    
    self.middleView = [[UIImageView alloc] initWithFrame:CGRectMake(KScreenWidth, 0, KScreenWidth, 300)];
    [self.middleView setImage:[_imagesArray objectAtIndex:0]];
    [_scrollView addSubview:_middleView];
    
    self.rightView = [[UIImageView alloc] initWithFrame:CGRectMake(2*KScreenWidth, 0, KScreenWidth, 300)];
    [self.rightView setImage:[_imagesArray objectAtIndex:1]];
    [_scrollView addSubview:_rightView];
    
    //设置小圆点
    self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(KScreenWidth/2-20, 350, 20, 20)];
    _pageControl.numberOfPages = 5;
    _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];
}

-(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
    _link.paused = YES;
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    //通过偏移量计算方向 等于零->向左  等于2->向右
    //NSLog(@"%f",scrollView.contentOffset.x);
    int direction = scrollView.contentOffset.x/KScreenWidth;
    if (direction == 0) {
        //向左
        if (_index == 0) {
            _index = 4;
        }else{
            _index --;
        }
    }else{
        //向右
        if (_index == 4) {
            _index = 0;
        }else{
            _index ++;
        }
    }
    _pageControl.currentPage = _index;
    NSArray *array = [NSArray arrayWithArray:[self getImgToShowByIndex:_index]];
    [_leftView setImage: [array objectAtIndex:0]];
    [_middleView setImage:[array objectAtIndex:1]];
    [_rightView setImage:[array objectAtIndex:2]];
    //将偏移值移回中间
    scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
    
    //两秒之后重新启动定时器
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(runLink) object:nil];
    [self performSelector:@selector(runLink) withObject:nil afterDelay:2];
}

//根据传来的值返回其左右的图像
-(NSMutableArray *)getImgToShowByIndex:(int )index{
    NSMutableArray *imgArray = [NSMutableArray array];
    
    
    if(index == 0){
        //第一张 4 0 1
        [imgArray addObject:[_imagesArray objectAtIndex:4]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:index +1]];
        
    }else if(index == 4){
        //最后一张 3 4 0
        [imgArray addObject:[_imagesArray objectAtIndex:index - 1]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:0]];
        
    }else{
        [imgArray addObject:[_imagesArray objectAtIndex:index -1]];
        [imgArray addObject:[_imagesArray objectAtIndex:index]];
        [imgArray addObject:[_imagesArray objectAtIndex:index +1]];
    }
    
    return imgArray;
}
#pragma ------------设置自动滚动--------------
-(void)setupLink{
    //设定一个定时器
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(slideImage)];
    _link.preferredFramesPerSecond = 1;
    [_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}

-(void)runLink{
    _link.paused = NO;
}

-(void)slideImage{
    
    //[_scrollView setContentOffset:CGPointMake(2*KScreenWidth, 0) animated:YES];
    
    //自动滚动一直往右滚
    if (_index == 4) {
        _index = 0;
    }else{
        _index ++;
    }
    _pageControl.currentPage = _index;
    
    NSArray *array = [NSArray arrayWithArray:[self getImgToShowByIndex:_index]];
    [_leftView setImage: [array objectAtIndex:0]];
    [_middleView setImage:[array objectAtIndex:1]];
    [_rightView setImage:[array objectAtIndex:2]];
    _scrollView.contentOffset = CGPointMake(KScreenWidth, 0);
}
@end

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