UIScrollView的一些特点
是个麻烦的控件,这里先问几个问题:
1.
答案是,如果所有view都是UIView的话,那么最外层的子view会先收到该消息。这个机制就是通过
2.
tableView继承自UIScrollView,这个功能实际上是UIScrollView来实现的。它是如何做的呢?根据问题 一,UIView的默认行为是将touch事件传递给最外层的subView。实际上UIScrollView重载了 hitTest:withEvent:,他永远只返回自己。
这里把UIScrollView的几个要点总结下:
从你的手指touch屏幕开始,scrollView开始一个timer,如果:
1.
2.
3. 150ms内手指没有滑动,scrollView将消息传给subView,但是之后手指开始滑动,scrollView传送touchesCancelled消息给subView,然后开始滚动。
观察下tableView的情况,你先按住一个cell,cell开始高亮,手不要放开,开始滑动,tableView开始滚动,高亮取消。
delaysContentTouches的作用:
这个标志默认是YES,使用上面的150ms的timer,如果设置为NO,touch事件立即传递给subView,不会有150ms的等待。
cancelsTouches的作用:
这个标准默认为YES,如果设置为NO,这消息一旦传递给subView,这scroll事件不会再发生。
UIScrollView的一些属性
1.
2.
边缘。。default is NO,
如果要只在水平反弹那么bounces必须为YES.
3.
反弹。default is no.
4.
或者是最小缩放倍数( minimumZoomScale)时,为了告诉用户缩放倍数已达极限,是否发生动态反弹的效果来
告诉用户。defaults is YES.
5.
再开始拖动,这个属性决定是否scorllView里的图片是否会再继续随着手指的滑动,而图片跟着滑动。defualt is
NO,图片会跟着手指滑动而滑动。
6.
frame属性里的原点(origin)的距离。按照一般思维来说,如scrollView的frame为(0,0,320,480),而scrollView里的
图片坐标为:(-320,0,320*2,480);那么contentOffset应该为(-320,0),但实际上是(320,0),可能是为了方便设置,取为
正吧,反正contentOffset的x,y是不可能为负的,那样代表滚动已到边缘,发生反弹或者不能再往边缘外拖动。
7.
大小,而要在里面存放几张屏幕大小的图片,那么一定不能忘了在放图片之前设置contentSize.
8.
当要实现缩放图片时,必须实现UIScrollViewDelegate里的两个方法,且最大、最小缩放倍数必须不一样maximumZoomScale
,minimumZoomScale:
- (UIView *)viewForZoomingInScrollVi
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
//重新确定缩放完后的缩放倍数.
常用来缩放方法:- (void)zoomToRect:(CGRect)rect animated:(BOOL)animated,把从scrollView里截取的矩形
区域缩放到整个scrollView当前可视的frame里面。所以如果截取的区域大于scrollView的frame时,图片缩小,
如果截取区域小于frame,会看到图片放大。一般情况下rect需要自己计算出来。
比如,要把scrollView原来坐标点为(40,40)的内容周围内容在scrollView里放大一倍,可以求出需要从scrollView里
截取图片的frame,当然主要是求截取图片坐标原点,可以想象,内容放大一倍,那么截取图片的大小宽度肯定是
scrollView的frame大小一半。如下列方法:
- (CGRect) getRectWithScale:(float)scale andCenter:(float)center
{
}
如果一开始拖动方向是水平或者垂直,且该属性设置为YES,那么另外一个方向将会被锁定,不能在那个方向拖动了。如果
开始拖动方向为斜的,那么不会禁止任何一个方向的拖动。
2.
显示的风格,当然也可以把这个滚动条取消。可以用下面属性:
@property(nonatomic) BOOL showsHorizontalScrollInd
@property(nonatomic) BOOL showsVerticalScrollIndic
3.
通常情况下,最小倍数比scrollView的frame要小,而最大缩放倍数可能与contentSize有关,需要自己算出
最大缩放倍数,如:如果想最大缩放倍数为5倍,那么contentSize也应该设置为5倍scrollView的frame大小。
假如想要双击scrollView里的图片放大,或者支持两只手指在屏幕捏放实现图片缩放,必须重写覆盖继承自
UIResponder的几个交互方法:
﹣(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
﹣(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
﹣(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
4.@property(nonatomic, getter=isPagingEnabled) BOOL pagingEnabled;
scrollView的下一个子视图开始边界. default is NO
@property(nonatomic, getter=isScrollEnabled) BOOL scrollEnabled;
如果设置为NO,那么将scrollView将不会接受任何触摸事件。
- (void)setZoomScale:(float)scale animated:(BOOL)animated
UIScrollView的用法
1.如果scrollView向下面滚动,一旦一排视图滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,也就是改变位置到达末尾,达到重用的效果。
2.如果scrollView向上面滚动,一旦最末排的视图view滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,移动到最前面。
- #define
sMyViewTotal 6 -
- #define
sMyViewWidth 150 -
- #define
sMyViewHeight 220 -
- #define
sMyViewGap 10
具体实现代码如下:
- _aryViews
= [[NSMutableArray alloc] init]; -
- for
(int i = 0; i < sMyViewTotal; i++) { -
-
CGFloat x; -
-
if (i%2) { -
-
x = sMyViewWidth + sMyViewGap + sMyViewGap/2; -
-
} -
-
else{ -
-
x = sMyViewGap/2; -
-
} -
-
CGFloat y = (sMyViewHeight + sMyViewGap)*(i/2); -
-
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(x, y, sMyViewWidth, sMyViewHeight)]; -
-
myView.showNumber = i; -
- [myScrollView
addSubview:myView]; -
-
[_aryViews addObject:myView]; -
-
[myView release]; -
- }
所以这里的核心方法是,首先要判断是向上滚动还是向下滚动方法如下:
- -
(void)scrollViewDidScroll:(UIScrollView *)scrollView{ -
-
BOOL directDown; -
-
if (previousOffSet.y < scrollView.contentOffset.y) { -
-
directDown = YES; -
-
} -
-
else{ -
-
directDown = NO; -
-
} -
-
previousOffSet.y = scrollView.contentOffset.y; -
-
//防止最开始就向上面拖动的时候,改变数组视图树的位置。 -
-
if (scrollView.contentOffset.y < 0) { -
-
return; -
-
} -
-
if (directDown) { -
-
NSLog(@"down"); -
-
MyView * subView = [_aryViews objectAtIndex:firstViewIndex]; -
-
CGFloat firstViewYOffset = subView.frame.origin.y + subView.frame.size.height + sMyViewGap; -
-
//寻找第一个视图是否滚动出去 -
-
if (firstViewYOffset < scrollView.contentOffset.y) { -
-
//改变数组中第一排可见视图的位置。 -
-
[self moveIndexInViewsWithDire ct:YES]; -
-
} -
-
} -
-
else{ -
-
NSLog(@"up"); -
-
MyView * subView = [_aryViews objectAtIndex:(firstViewIndex + sMyViewTotal - 2)%sMyViewTotal]; -
-
CGFloat lastViewYOffset = subView.frame.origin.y - scrollView.bounds.size.height; -
-
if (lastViewYOffset > scrollView.contentOffset.y) { -
-
[self moveIndexInViewsWithDire ct:NO]; -
-
} -
-
} -
- }
每次滚动的时候先判断滚动位置即offset,和先前的比较。如果先前的大就是向下滚动,否则就是向上滚动。
- -
(void)moveIndexInViewsWithDire ct:(BOOL)forward{ -
-
[UIView setAnimationsEnabled:NO]; -
-
if (forward) { -
-
for (int i = firstViewIndex; i < (firstViewIndex + 2); i++) { -
-
MyView *subView = [_aryViews objectAtIndex:i%sMyViewTotal]; -
-
subView.showNumber = subView.showNumber + sMyViewTotal; -
- subView.frame
= CGRectMake(subView.frame.origin.x, subView.frame.origin.y + (sMyViewTotal/2) * (sMyViewHeight + sMyViewGap), subView.frame.size.width, subView.frame.size.height); -
-
} -
-
firstViewIndex = (firstViewIndex + 2)%sMyViewTotal; -
-
} -
-
else{ -
-
int lastViewIndex = firstViewIndex + sMyViewTotal - 1; -
-
for (int i = lastViewIndex; i > (lastViewIndex - 2); i--) { MyView *subView = [_aryViews objectAtIndex:(firstViewIndex + sMyViewTotal - i)%sMyViewTotal]; -
-
subView.showNumber = subView.showNumber - sMyViewTotal; -
- subView.frame
= CGRectMake(subView.frame.origin.x, subView.frame.origin.y - (sMyViewTotal/2) * (sMyViewHeight + sMyViewGap), subView.frame.size.width, subView.frame.size.height); -
-
} -
-
firstViewIndex = (firstViewIndex + sMyViewTotal - 2)%sMyViewTotal; -
-
} -
-
[UIView setAnimationsEnabled:YES]; -
- }
- -
(void)drawRect:(CGRect)rect -
- {
-
-
// Drawing code -
-
NSString *text = [NSString stringWithFormat:@"%d",showNumber]; -
-
[[UIColor redColor] set]; -
-
[text drawInRect:CGRectMake(rect.origin.x, rect.origin.y + rect.size.height/2 - 30, rect.size.width, 30) withFont:[UIFont fontWithName:@"Helvetica" size:20] lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter]; -
- }
-
- }