2011-11-05. 我终于闲下来,写了一个Demo,打包,欢迎大家下载
InfiniteScroll.zip (18.1 KB, 478 次)
最近开发一个ipad/iphone应用,要用到无缝循环滚动,网上搜了一下uiscrollview循环滚动,都是那么一个帖子转来转去,循环的时候其实没法无缝,只好自己实现一个。
头文件:
1
2
3
4
5
6
7
8
9
10
11
12
|
#import
@class
ArticleViewController;
@interface
ArticleScrollViewController
:
UIViewController
{
//不使用数组,看起来更明了,为了节省内存同时还要看起来无缝,3个view最好
ArticleViewController *article1;
ArticleViewController *article2;
ArticleViewController *article3;
}
@end
|
实现:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#import "ArticleScrollViewController.h"
#import "ArticleViewController.h"
#import "ViewSwitcher.h"
@implementation
ArticleScrollViewController
// vieDidLoad函数不重要,只要初始化了三个view并放在uiscrollview里面,正确设定uiscrollview的content size就行了
- (
void
)viewDidLoad {
[
super
viewDidLoad
];
UIScrollView
*scrollView = (
UIScrollView
*)
self
.view;
scrollView.contentSize =
CGSizeMake
(
self
.view.frame.size.width
*3
,
self
.view.frame.size.height);
CGRect
frame =
self
.view.frame;
frame.origin.y =
0
.0f
;
NSInteger
article2Index = [ViewSwitcher
getInstance
].currentArticleIndex;
NSInteger
article1Index = article2Index -
1
;
article1Index = article1Index <
0
? [ViewSwitcher
getInstance
].articleCount -
1
: article1Index;
article1Index = article1Index >= [ViewSwitcher
getInstance
].articleCount ?
0
: article1Index;
NSInteger
article3Index = article2Index +
1
;
article3Index = article3Index <
0
? [ViewSwitcher
getInstance
].articleCount -
1
: article3Index;
article3Index = article3Index >= [ViewSwitcher
getInstance
].articleCount ?
0
: article3Index;
article1 = [[ArticleViewController
alloc
]
initWithArticleIndex
:article1Index];
[article1.view
setFrame
:frame];
article2 = [[ArticleViewController
alloc
]
initWithArticleIndex
:article2Index];
frame.origin.x +=
self
.view.frame.size.width;
[article2.view
setFrame
:frame];
article3 = [[ArticleViewController
alloc
]
initWithArticleIndex
:article3Index];
frame.origin.x +=
self
.view.frame.size.width;
[article3.view
setFrame
:frame];
[scrollView
addSubview
:article1.view];
[scrollView
addSubview
:article2.view];
[scrollView
addSubview
:article3.view];
CGPoint
p =
CGPointZero
;
p.x = scrollView.frame.size.width;
[scrollView
setContentOffset
:p
animated
:
NO
];
[article2
reloadData
];
}
#pragma mark -
#pragma mark UIScrollViewDelegate
#define SET_FRAME(ARTICLEX) x = ARTICLEX.view.frame.origin.x + increase;\
if
(x <
0
) x = pageWidth *
2
;\
if
(x > pageWidth *
2
) x =
0
.0f
;\
[ARTICLEX.view
setFrame
:
CGRectMake
(x, \
ARTICLEX.view.frame.origin.y,\
ARTICLEX.view.frame.size.width,\
ARTICLEX.view.frame.size.height)]
//将三个view都向右移动,并更新三个指针的指向,article2永远指向当前显示的view,article1是左边的,article3是右边的
- (
void
)allArticlesMoveRight:(
CGFloat
)pageWidth {
//上一篇
article3.articleIndex = article1.articleIndex -
1
;
if
(article3.articleIndex <
0
) {
article3.articleIndex = [ViewSwitcher
getInstance
].articleCount -
1
;
}
[article1
reloadData
];
ArticleViewController *tmpArticleViewController = article3;
article3 = article2;
article2 = article1;
article1 = tmpArticleViewController;
float
increase = pageWidth;
CGFloat
x =
0
.0f
;
SET_FRAME(article3);
SET_FRAME(article1);
SET_FRAME(article2);
}
- (
void
)allArticlesMoveLeft:(
CGFloat
)pageWidth {
article1.articleIndex = article3.articleIndex +
1
;
if
(article1.articleIndex >= [ViewSwitcher
getInstance
].articleCount) {
article1.articleIndex =
0
;
}
[article3
reloadData
];
//[article2 resetView];[article3 resetView];
ArticleViewController *tmpArticleViewController = article1;
article1 = article2;
article2 = article3;
article3 = tmpArticleViewController;
float
increase = -pageWidth;
CGFloat
x =
0
.0f
;
SET_FRAME(article2);
SET_FRAME(article3);
SET_FRAME(article1);
}
/*
循环滚动
每次滚动后都将scrollview的offset设置为中间的一页
若本次滚动是向前一页滚动,则把三页都向后放置,最后一页放到开头
若本次滚动是向后一页滚动,则把三页都向前放置,第一页放到末尾
*/
- (
void
)scrollViewDidEndDecelerating:(
UIScrollView
*)theScrollView
{
CGFloat
pageWidth = theScrollView.frame.size.width;
// 0 1 2
int
page = floor((theScrollView.contentOffset.x - pageWidth /
2
) / pageWidth) +
1
;
if
(page ==
1
) {
//用户拖动了,但是滚动事件没有生效
return
;
}
else
if
(page ==
0
) {
[
self
allArticlesMoveRight
:pageWidth];
}
else
{
[
self
allArticlesMoveLeft
:pageWidth];
}
CGPoint
p =
CGPointZero
;
p.x = pageWidth;
[theScrollView
setContentOffset
:p
animated
:
NO
];
[article1
resetView
];
[article3
resetView
];
}
#pragma mark -
#pragma mark dealloc
- (
void
)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[
super
didReceiveMemoryWarning
];
// Release any cached data, images, etc. that aren't in use.
}
- (
void
)viewDidUnload {
[
super
viewDidUnload
];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[article1 release];article1 =
nil
;
[article2 release];article2 =
nil
;
[article3 release];article3 =
nil
;
}
- (
void
)dealloc {
[article1 release];
[article2 release];
[article3 release];
[
super
dealloc
];
}
@end
|
这里的雕虫小技主要在于:
以手指向右拖动为例,【屏幕】指的是scorllview的显示区域
article1 article2 article3 【屏幕】
拖动以后成这样:
article1 article2 article3 【屏幕】
将article3放到第一个去(设定article3的frame),这是屏幕还显示的是article1的内容
article3 article1 article2 【屏幕】
将屏幕移到中间:使用setContentOffset,禁用动画,这样骗过人眼
article3 article1 article2 【屏幕】
最后更新指针顺序:
article1 article2 article3 【屏幕】
无缝循环实现了。