iOS开发中使用UIScrollView实现无限滚动实例分享

作者:简简单单 2015-06-16

实例一 iOS开发中UIScrollView支持无限滚动

默认的UIScrollView滑动到底之后(假设往右),就无法继续往右滑了,但为了更好的用户体验,我们继续往右滑是自动回到第一页。这里提供一个方案。

假设有5页,其中分别放着1.jpg 2.jpg 3.jpg 4.jpg 5.jpg五张图,为支持无限滚动,我们把最后一张图复制一份追加到第一张左边,把第一张图复制一份追加到最后一张图右边,即新的UIScrollView有7页,分别是

[1号:5.jpg][2号:1.jpg][3号:2.jpg][4号:3.jpg][5号:4.jpg][6号:5.jpg][7号:1.jpg]

然后把初始的位置移动到2号。接下来,如果用户滑动到7号位置,则立刻把位置更换到2号,此时用户并没有发现位置发生了改变,从而实现了无限往右滚。同理,如果用户滑动到1号位置,则立刻把位置更换到6号,实现无限往左滚。至此,实现了无限滚动。

在Objective-C中的实现方案:

    // 通过补充前后两张图片完成scrollView的初始化,并正确设置contentSize
    // code..
    // 移动到2号位置:
    [scrollView scrollRectToVisible:CGRectMake(scrollView.bounds.size.width,0,scrollView.bounds.size.width,scrollView.bounds.size.height) animated:NO];
    // 设置delegate
    scrollView.delegate = self;

然后添加以下函数获取用户滑动scrollView并停止的动作(以下函数一般无需修改即可使用)

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        if (scrollView.contentOffset.x == 0) {
            // 用户滑动到1号位置,此时必须跳转到倒二的位置
            [scrollView scrollRectToVisible:CGRectMake(scrollView.contentSize.width - 2 * scrollView.bounds.size.width,0,scrollView.bounds.size.width,scrollView.bounds.size.height) animated:NO];
        }
        else if (scrollView.contentOffset.x == scrollView.contentSize.width - scrollView.bounds.size.width) {
            // 用户滑动到最后的位置,此时必须跳转到2号位置
            [scrollView scrollRectToVisible:CGRectMake(scrollView.bounds.size.width,0,scrollView.bounds.size.width,scrollView.bounds.size.height) animated:NO];
        }
    }

实例二 iOS-利用UIScrollView实现展示图片的无限滚动及自动滚动

//
  2 //  GXViewController.m
  3 //  自动滚动及无线循环
  4 //
  5 //  Created by 郭晓 on 14-3-7.
  6 //  Copyright (c) 2014年 郭晓. All rights reserved.
  7 //
  8
  9 #import "GXViewController.h"
 10
 11 #define kCount 6  //图片总张数
 12
 13 static long step = 0; //记录时钟动画调用次数
 14
 15 @interface GXViewController ()
 16 {
 17     UIScrollView *_scrollView;
 18     UIImageView     *_currentImageView; //当前视图
 19     UIImageView     *_nextImageView;    //下一个视图
 20     UIImageView     *_previousView;     //上一个视图
 21     CADisplayLink   *_timer;            //定时器
 22     
 23     BOOL _isDraging; //当前是否正在拖拽
 24 }
 25
 26 @end
 27
 28 @implementation GXViewController
 29
 30 - (void)viewDidLoad
 31 {
 32     [super viewDidLoad];
 33     
 34     CGFloat 01.jpg"];
 49     _currentImageView.frame = CGRectMake(width, 0, width, height);
 50     _currentImageView.contentMode = UIViewContentModeScaleAspectFill;
 51     [_scrollView addSubview:_currentImageView];
 52     
 53     //初始化下一个视图
 54     _nextImageView = [[UIImageView alloc] init];
 55     _nextImageView.image = [UIImage imageNamed:@"02.jpg"];
 56     _nextImageView.frame = CGRectMake(width * 2, 0, width, height);
 57     _nextImageView.contentMode = UIViewContentModeScaleAspectFill;
 58     [_scrollView addSubview:_nextImageView];
 59     
 60     //初始化上一个视图
 61     _previousView = [[UIImageView alloc] init];
 62     _previousView.image = [UIImage imageNamed:@"06.jpg"];
 63     _previousView.frame = CGRectMake(0, 0, width, height);
 64     _previousView.contentMode = UIViewContentModeScaleAspectFill;
 65     [_scrollView addSubview:_previousView];
 66     
 67     // 时钟动画
 68     _timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(update:)];
 69     [_timer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
 70     
 71 }
 72
 73 #pragma mark 时钟动画调用方法
 74 - (void)update:(CADisplayLink *)timer
 75 {
 76     step++;
 77     
 78     if ((step % 120 != 0) || _isDraging) {
 79         return;
 80     }
 81     
 82     CGPoint offset = _scrollView.contentOffset;
 83     
 84     offset.x += 320;
 85     if (offset.x > 640) {
 86         offset.x = 320;
 87     }
 88     
 89     [_scrollView setContentOffset:offset animated:YES];
 90 }
 91
 92 #pragma mark - 代理方法
 93 #pragma mark 准备开始拖动
 94 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
 95 {
 96     _isDraging = YES;
 97 }
 98
 99 #pragma mark 视图停止滚动
100 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
101 {
102     _isDraging = NO;
103     step = 0;
104 }
105
106 #pragma mark 已经拖动
107 - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
108     
109     static int i = 1;//当前展示的是第几张图片
110     
111     float offset = scrollView.contentOffset.x;
112     if (_nextImageView.image == nil || _previousView.image == nil) {
113         
114         //加载下一个视图
115         NSString *imageName1 = [NSString stringWithFormat:@"0%d.jpg", i == kCount ? 1 : i + 1];
116         _nextImageView.image = [UIImage imageNamed:imageName1];
117         
118         //加载上一个视图
119         NSString *imageName2 = [NSString stringWithFormat:@"0%d.jpg", i == 1 ? kCount : i - 1];
120         _previousView.image = [UIImage imageNamed:imageName2];
121     }
122     
123     if (offset == 0) {
124         _currentImageView.image = _previousView.image;
125         scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
126         _previousView.image = nil;
127         
128         if (i == 1) {
129             i = kCount;
130         }else{
131             i -= 1;
132         }
133         
134     }
135     
136     if (offset == scrollView.bounds.size.width * 2) {
137         _currentImageView.image = _nextImageView.image;
138         scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
139         _nextImageView.image = nil;
140         
141         if (i == kCount) {
142             i = 1;
143         }else{
144             i += 1;
145         }
146         
147     }
148 }
149
150 @end

注意:在代码中,使用到了6张用于展示的图片,图片名分别为01、02、03、04、05、06.
通过以上代码,就可以实现图片的无限滚动及自动滚动功能,之所以用CADisplayLink而不用NSTimer是因为NSTimer的时间不够准确。

实例三 iOS_UIScrollView实现无限滚动,思路与代码

UIScrollView实现无限滚动的三种思路。

当然只是我的一些用法,当然还有非常多的实现方式,如果大家有好的实现思路也可以告诉我,相互学习嘛~

UIScrollView无限滚动

第一种方式:

原理:利用结束的位置来重新设置ScrollView ContentOffset的值,让人产生视觉上的无限循环,优点:代码易懂,缺点,会创建多余的内存。

第二种方式:

原理:利用中间的两个变量来当前的View及缓冲的View,只创建两个View,将当前的View放在中间。判断滑动的位置,优先去缓冲的View找,然后结束滑动在更新当前View的image

第三种方式(这里就不讲解了):

原理:利用CollectionView来实现,代码也非常简单。一次性给数据源传入 images.count * 1000,然后默认加载的时候,跳转到 (images.count * 1000)/2.0 + ((images.count * 1000)/2.0) % images.count的位置就实现了


github代码地址:https://github.com/MakeZL/UIScrollViewLoopDemo点击打开链接


好了。我们先看第一种实现比较简单的

/**
 *          
 第一种方式:
    利用结束的位置来重新设置ScrollView ContentOffset的值,让人产生视觉上的无限循环
    优点:代码易懂
    缺点,会创建多余的内存。
 */
- (void)realizeScrollLoop1{
     
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.pagingEnabled = YES;
    scrollView.frame = self.view.bounds ;
    scrollView.delegate = self;
    [self.view addSubview:scrollView];
    self.scrollView = scrollView;
    [scrollView setContentSize:CGSizeMake(([self.slideImages count] + 2) * scrollView.frame.size.width, 0)];
     
    CGSize scrollViewSize = scrollView.frame.size;
     
    // 遍历创建子控件
    [self.slideImages enumerateObjectsUsingBlock:^(NSString *imageName, NSUInteger idx, BOOL *stop) {
        UIImageView *imageView = [[UIImageView alloc] init];
        imageView.image = [UIImage imageNamed:imageName];
        imageView.frame = CGRectMake((idx+1) * scrollViewSize.width, 0, scrollViewSize.width, scrollViewSize.height);
        [scrollView addSubview:imageView];
    }];
     
    // 将最后一张图片弄到第一张的位置
    UIImageView *imageView = [[UIImageView alloc] init];
    imageView.image = [UIImage imageNamed:
                       self.slideImages[[self.slideImages count] - 1]];
    imageView.frame = CGRectMake(0, 0, scrollViewSize.width, scrollViewSize.height);
    [scrollView addSubview:imageView];
     
    // 将第一张图片放到最后位置,造成视觉上的循环
    UIImageView *lastImageView = [[UIImageView alloc] init];
    lastImageView.image = [UIImage imageNamed:
                           self.slideImages[0]];
    lastImageView.frame = CGRectMake(scrollViewSize.width * ([self.slideImages count] + 1), 0, scrollViewSize.width, scrollViewSize.height);
    [scrollView addSubview:lastImageView];
     
    [scrollView setContentOffset:CGPointMake(scrollViewSize.width, 0)];
}



然后再UIScrollView的delegate里面实现即可

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
    NSInteger page = scrollView.contentOffset.x / scrollView.frame.size.width;
    // 如果当前页是第0页就跳转到数组中最后一个地方进行跳转
    if (page == 0) {
        [scrollView setContentOffset:CGPointMake(scrollView.frame.size.width * ([[self slideImages] count]), 0)];
    }else if (page == [[self slideImages] count] + 1){
        // 如果是第最后一页就跳转到数组第一个元素的地点
        [scrollView setContentOffset:CGPointMake(scrollView.frame.size.width, 0)];
    }
}




是不是很简单。下面我们来看第二种


第二种方式,带缓存:

/**
 *  
    第二种方式:
        利用中间的两个变量来当前的View及缓冲的View,最多创建三个View,将当前的View放在中间。判断滑动的位置,优先去缓冲的View找
        优点:对内存消耗少,缺点:代码相比要复杂一丝丝
 */
- (void) realizeScrollLoop2{
     
    status = ScrollViewLoopStatusResuing;
     
    UIScrollView *scrollView = [[UIScrollView alloc] init];
    scrollView.pagingEnabled = YES;
    scrollView.frame = self.view.bounds ;
    scrollView.delegate = self;
    [self.view addSubview:scrollView];
    self.scrollView = scrollView;
     
    CGSize scrollViewSize = scrollView.frame.size;
    scrollView.contentSize = CGSizeMake(3 * scrollViewSize.width, 0);
    scrollView.contentOffset = CGPointMake(scrollViewSize.width, 0);
     
    UIImageView *currentView = [[UIImageView alloc] init];
    currentView.tag = 0;
    currentView.frame = CGRectMake(scrollViewSize.width, 0, scrollViewSize.width, scrollViewSize.height);
    currentView.image = [UIImage imageNamed:@"00.jpg"];
    [scrollView addSubview:currentView];
    self.currentView = currentView;
     
    [self resuingView];
    self.index = 0;
     
}


实现UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    if (status == ScrollViewLoopStatusResuing) {
        if (scrollView.contentOffset.x > _currentView.frame.origin.x) {
             
            NSInteger val = self.index + 1;
            if (self.index >= [self.slideImages count] - 1) {
                val = 0;
            }
             
            // 取缓冲区的View
            self.resuingView.image = [UIImage imageNamed:[NSString stringWithFormat:@"0%zd.jpg",val]];
            self.resuingView.x = CGRectGetMinX(_currentView.frame) + _currentView.width;
            self.isLastScrollDirection = YES;
        }else{
            NSInteger val = self.index - 1;
            if (val < 0) {
                val = [self.slideImages count]-1;
            }
            self.resuingView.image = [UIImage imageNamed:[NSString stringWithFormat:@"0%zd.jpg",val]];
            self.resuingView.x = 0;
            self.isLastScrollDirection = NO;
        }
    }
}



要再结束的时候把当前currentView的image赋值最新的。

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
     
    // 是否是往右边滑动
    if (self.isLastScrollDirection) {
        self.index++;
    }else{
        self.index--;
    }
     
    // 补全
    if (self.index < 0) {
        self.index = [self.slideImages count]-1;
    } else if(self.index > [self.slideImages count]-1){
        self.index = 0;
    }
     
    _currentView.image = [UIImage imageNamed:[NSString stringWithFormat:@"0%zd.jpg",self.index]];
 
}



这样就能实现无限循环了

相关文章

精彩推荐