实例一 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]];
}
这样就能实现无限循环了