标签:
一,创建和配置Scroll Views:
1,创建Scroll Views:
Scroll views的创建和其他view一样,通过代码或IB。只需要一点附加的配置来获得基本的scrolling能力。
1)你必须设置contentSize属性。这个属性指定了可滑动区域的尺寸。
2)你必须向Scroll views增加一个view或views来让其显示和滚动。
2,在IB中创建Scroll views:
拖动一个UIScrollView到目标区域。然后连接出口即可。
虽然IB中的UIScrollView属性检查器允许你设置Scroll view的很多属性,你仍然需要在你的应用程序代码中负责设置contentSize属性,它定义了可滑动的区域。你可以在viewDidLoad方法中设置。
Listing 1-1 设置a scroll view’s size
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(1280,960);
}
在设置了ScrollView的尺寸后,你的应用程序可以通过代码或在IB中添加必须的subview。
3,通过代码创建ScrollView:
Listing 1-2 通过代码创建ScrollView
- (void)loadView {
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
scrollView=[[UIScrollView alloc] initWithFrame:fullScreenRect];
scrollView.contentSize=CGSizeMake(320,758);
// do any further configuration to the scroll view
// add a view, or views, as a subview of the scroll view.
// release scrollView as self.view retains it
self.view=scrollView;
[scrollView release];
}
4,添加Subviews:
无论你是使用一个子视图还是多个子视图,你都要面临一个决策性的设计:你的scrollView需要支持缩放吗?
如果你准备支持缩放,通用的技术是使用一个单子视图覆盖整个contentSize,然后添加其他的子视图到这个view中。这允许你指定一个单独的”colloection”内容视图来进行缩放,并且其所有的子视图会根据它的状态进行缩放。
如果不支持缩放,这就无关紧要了。
5,配置ScrollView的Content Size,Content Inset和Scroll Indicators:
contentSize属性是需要展示的内容区域的大小。
你
或许向添加围绕scrollView边缘的padding,一般在顶部和底部设置,以便controllers和toolbars不会干扰查看整个
scrollView的内容.要添加padding,你必须设置contentInset属性。contentInset属性指定一个围绕在
scrollView的内容周围的buffer
area。理解它的一个方法是,它使得scrollView的内容区域变大了,而无需更改其subView或其本身的尺寸。
contentInset属性是一个 UIEdgeInsets结构,包括top,bottom,left,right字段。如下图所示:
上
图指定了contentInset属性为(64,44,0,0),指定了顶部的64像素的buffer area(20px为status
bar和44px为navigation controller的高度) ,和44px的底部的buffer area(
44px为toolbar的高度).设置语句如下:
scrollView.contentInset=UIEdgeInsetsMake(64.0,0.0,44.0,0.0);
(contentInset属性应该是增加scrollview的可滚动区域,但是内容不会显示在contentInset区域内,所以在注册键盘弹出事件时,一般先给scrollView增加一个键盘高度的contentInset)
然
而,更改contentInset的值对显示scroll Indicator有一个非预期的影响。当你拖动scroll
view时,会显示滚动指示器(scroll
indicator).滚动指示器会显示于任何显示在contentInset定义的区域内的视图之下,如navigation
Control和toolbar会遮挡滚动指示器的显示。
要修正这个,你必须设置scrollIndicatorInsets属性。scrollIndicatorInsets属性也是一个UIEdgeInSets结构。一般将这个属性设置成和contentInset属性一致,以正确显示滚动指示器。
scrollView.scrollIndicatorInsets=UIEdgeInsetsMake(64.0,0.0,44.0,0.0);
二,滚动ScrollView的内容
用
户操作有drag,flick(快速移动).flick手势操作不仅引起scroll
view的滚动,而且引起一个动力,基于移动的速度,虽然手势完了,但是滚动一直继续,直到减速为0时停止。在减速期间,用户可以触摸屏幕以停止滚动在某
处。所有这些行为已经内嵌于UIScrollView,并且无需开发人员实现。
但有时需要使用代码滑动内容,展示文档的某一特定的部分。在这些情况下,UIScrollView提供了必须的方法。
UIScrollView的代理协议UIScrollViewDelegate提供了方法,允许你的代码跟踪滚动进度和正确响应。
1,滚动到一个特定的偏移距离:滚动到一个特定的top-left(距离左上角的)位置(contentOffset属性)可以通过两种方法完成:
a)方法setContentOffset:animated: 无论是否动画,代理都被发送一个scrollViewDidScroll:消息。如果动画被禁用,或者你直接设置了contentOffset属性,代理只接收到一个单独的scrollViewDidScroll:消息,如果启用了动画,代理将在动画执行期间收到一系列的scrollViewDidScroll:消息。当动画执行完毕后,代理收到一个scrollViewDidEndScrollingAnimation:消息。
B)使矩形可见:这在你的应用需要显示一个特定的控制视图时非常有用。方法scrollRectToVisible:animated: 滚动指定的矩形以使其正好显示在scroll View中。委托收到的消息同上。
2,滚动到顶部:如果status bar可见,那么可以通过轻击status bar来快速滚动scroll view到顶部。你的应用要更改这个特性,需要实现代理方法scrollViewShouldScrollToTop:并返回YES或NO。
当滚动完成时,代理被发送一个scrollViewDidScrollToTop:消息。
3,在滚动时委托被发送的消息:当滚动发生时,scrollView跟踪其状态,通过使用tracking,dragging,decelerating,和zooming属性。另外,contentOffset属性定义了可见内容的top-left点(这个属性是实时改变的)。下面的表格描述了每个状态属性:
属性 描述
tracking YES—如果用户的手指在接触屏幕
dragging YES—如果用户的手指接触屏幕并且移动
decelerating YES—如果scrollView正在减速动画
zomming YES—如果scrollView正在tracking一个捏合手势来更改其zoomScale属性
contentOffset 一个到scroll View bounds的左上角的CGPoint
没有必要轮询这些属性来确定正在进行的动作因为scrollview发送详细的一系列消息给代理,来指示滚动动作的进度。委托方法可以查询这些状态属性来确定为什么接收到消息或scrollview当前在哪里。
4,简单的途径:跟踪一个滚动动作的开始和结束:如果你的应用只关心滚动过程的开始和结束,你可以只实现很少的几个委托方法:
1)实现 scrollViewWillBeginDragging:来接收拖动将要开始的通知。
2)要确定滚动是否已经停止,你必须实现两个委托方法:scrollViewDidEndDragging:willDecelerate:和scrollViewDidEndDecelerating: .当委托收到scrollViewDidEndDragging:willDecelerate:消息并且decelerate参数为NO,或者当委托收到scrollViewDidEndDecelerating:方法时,滚动就结束了。
5,完全的委托消息序列:
当用户触摸屏幕时,tracking sequence就开始了。Tracking属性被立即设置为YES,并在用户手指触摸屏幕期间保持YES,无论是否移动了手指。
如果用户的手指保持静止,并且内容视图响应触摸事件,它应该处理触摸,并且序列完成。
然而,如果用户移动了手指,序列就继续进行。
当用户开始移动手指来发起滚动scrollview的第一次尝试(假定scrollview的默认值)来取消任何触摸处理进度,如果它尝试这么做。
(注
意:贯穿整个消息序列,这是可能的—即tracking和dragging属性一直为NO,并且zooming属性为YES。这发生于当缩放动作的结果导
致scrolling发生时,无论Scrolling是被一个手势引起还是通过代码引起。作为zooming或scrolling的结果,如果代理被发送
消息,你的应用或许选择采取不同的行动。)
scrollView的dragging属性设置为YES,并且发送给代理 scrollViewWillBeginDragging:消息。
随
着用户拖动其手指,scrollViewDidScroll:消息发送给其代理。在滚动期间,这个消息持续的发送。这个方法的你的实现可以查询
scrollView的contentOffset属性来确定scrollView的bounds的左上角。ContentOffset属性一直是
scroll bounds的左上角位置,无论是否正在滚动。
(总结1:即普通拖动手指(不是缩放),信息序列为:
1)手指放到屏幕上Tracking=YES。如果scrollView正在滚动,那么这会引起scrollView停止滚动,代理会收到scrollViewDidEndDecelerating:消息。
2)如果用户开始拖动手指,dragging=YES同时scrollViewWillBeginDragging: 消息发出。代理可以取消拖动
3)如果允许拖动,那么消息scrollViewDidScroll:持续发送给代理,你可以通过contentOffset属性来帮助你处理该消息。
4)拖动完成,代理收到scrollViewDidEndDragging:willDecelerate: 并且第二个参数为NO,表示拖动结束。
5)
如果用户的操作是flick(即快速滑动了手指,并离开屏幕),那么代理收到
scrollViewDidEndDragging:willDecelerate:,并且第二个参数为NO,表示拖动结束,开始减速。此时
Tracking=NO,委托收到scrollViewWillBeginDecelerating:消息,在减速期间,委托持续收到
scrollViewDidScroll:消息,并在减速结束后,委托收到scrollViewDidEndDecelerating:消息
6)如果是使用代码setContentOffset:animated:或scrollRectToVisible:animated: 导致的scrollView滚动,如果动画被禁用,或者你直接设置了contentOffset属性,代理只接收到一个单独的scrollViewDidScroll:消息,如果启用了动画,代理将在动画执行期间收到一系列的scrollViewDidScroll:消息。当动画执行完毕后,代理收到一个scrollViewDidEndScrollingAnimation:消息。
)
如
果用户执行了一个flick手势,tracking属性被设置为NO,因为为了执行flick手势,用户的手指必须离开屏幕。这是委托收到
scrollViewDidDragging:willDecelerate:消息。在滚动减速时参数deceleration将是YES。减速度通过decelerationRate属性控制。默认地,这个属性被设置为UIScrollViewDecelerationRateNormal。你可以设置其为UISCrollViewDecelerationFast来加快减速。在减速期间,decelerating属性为YES。
如果用户拖动,停止拖动并且离开屏幕,委托将收到scrollViewDidEndDragging:willDecelerate:消息,deceleration参数为NO。这是因为没有引起冲力。因为用户的手指已经不再屏幕上,tracking属性为NO。
如果scrollViewDidEndDragging:willDecelerate:消息的减速参数为NO,然后委托将不再收到这个拖动操作的委托消息。ScrollView的decelerating属性现在也返回NO。
还
有一个情况导致scrollViewDidEndDragging:willDecelerate:消息发送给代理,甚至用户已经在静止状态下提高了手
指。如果scroll View被配置为提供可见的cue of bouncing ----当用户拖动内容超出scrolling
area的边缘时,scrollViewDidEndDragging:willDecelerate:消息被发送给代理并且deceleration参
数为YES。当bounces属性为YES(默认值)时Bouncing被启用。当bounces属性为NO时,alwaysBounceVertical和alwaysBounceHorizontal属性不影响scrollview的行为。当bounces属性为YES时,当contentSize属性小于scroll view的bounds时,他们允许bouncing。
不
管哪种情况导致scroll
view接收scrollViewDidEndDragging:willDecelerate:消息,如果deceleration参数为
YES,scroll
view都被发送scrollViewWillBeginDecelerating:消息。在减速期间,委托持续收到
scrollViewDidScroll:消息,虽然tracking和dragging属性都是NO。decelerating属性持续为YES。
最终,当ScrollView减速完成时,委托被发送一个scrollViewDidEndDecelerating:消息,并且decelerating属性为NO,并且滚动序列完成。
三、使用捏合手势基本的缩放
UIScrollView支持捏合手势,你的应用指定缩放因子并且你实现一个单独的委托方法。
1,支持捏合缩放手势:
要支持缩放,你必须为你的ScrollView设置一个代理。代理必须遵循UIScrollViewDelegate协议。代理类必须实现viewForZoomingInScrollView:方法并且返回要zoom的view。
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
要指定用户可以缩放的amount,你可以设置minimumZoomScale和maximumZoomScale属性,他们默认为1.0.可以在IB中设置这些值,或通过代码。
指定缩放因子和代理实现viewForZoomingInScrollView:方法是实现缩放的最小的要求。
2, 通过代码缩放:一个scrollView可能需要缩放来响应触摸事件,例如双击或其他轻击手势,或响应另外一个用户动作而不是捏合手势。要允许这 些,UIScrollView提供了一个两个实现方法:setZoomScale:animted:和zoomToRect:animated:
setZoomScale:animted:
设置当前的zoom
scale为指定值。值必须在指定的minimumZoomScale和maximumZoomScale之间,还可以直接设置zoomScale属性,
相当于参数为NO。当缩放时,被缩放的view的中心保持不变。
zoomToRect:animated:方法缩放内容来填充指定的矩形。下面是例子:
Listing 3-2 A utility method that converts a specified scale and center point to a rectangle for zooming
- (CGRect)zoomRectForScrollView:(UIScrollView *)scrollView withScale:(float)scale withCenter:(CGPoint)center {
CGRect zoomRect;
// The zoom rect is in the content view‘s coordinates.
// At a zoom scale of 1.0, it would be the size of the
// imageScrollView‘s bounds.
// As the zoom scale decreases, so more content is visible,
// the size of the rect grows.
zoomRect.size.height = scrollView.frame.size.height / scale;
zoomRect.size.width = scrollView.frame.size.width / scale;
// choose an origin so as to get the right center.
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
}
3,通知代理缩放完成:代理收到 scrollViewDidEndZooming:withView:atScale:消息。
4,确保被缩放的内容is Sharp—当其被缩放时:
当
scrollView的内容被缩放时,被缩放的视图内容只是简单地被缩放。这只是创建更大或更小的内容,但不导致内容重画。结果是,显示的内容is
not displayed sharply。当缩放的内容是一幅图像时,并且你的应用并不显示新的,更详细的内容,例如地图应用,这可能不一个问题。
然
而,如果你缩放的内容被实时绘制,并且需要在被缩放时显示sharply,你的应用需要使用Core Animation。它需要更改Core
Animation---通过UIView的layer to CATileLayer and 通过Core
Animation的drawLayer:inContext:方法绘制。
Listing 3-3 Implementation of a UIView Subclass That Draw’s Its Content Sharply During Zoom
#import "ZoomableView.h"
#import <QuartzCore/QuartzCore.h>
@implementation ZoomableView
// Set the UIView layer to CATiledLayer
+(Class)layerClass
{
return [CATiledLayer class];
}
// Initialize the layer by setting
// the levelsOfDetailBias of bias and levelsOfDetail
// of the tiled layer
-(id)initWithFrame:(CGRect)r
{
self = [super initWithFrame:r];
if(self) {
CATiledLayer *tempTiledLayer = (CATiledLayer*)self.layer;
tempTiledLayer.levelsOfDetail = 5;
tempTiledLayer.levelsOfDetailBias = 2;
self.opaque=YES;
}
return self;
}
// Implement -drawRect: so that the UIView class works correctly
// Real drawing work is done in -drawLayer:inContext
-(void)drawRect:(CGRect)r
{
}
-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
// The context is appropriately scaled and translated such that you can draw to this context
// as if you were drawing to the entire layer and the correct content will be rendered.
// We assume the current CTM will be a non-rotated uniformly scaled
// affine transform, which implies that
// a == d and b == c == 0
// CGFloat scale = CGContextGetCTM(context).a;
// While not used here, it may be useful in other situations.
// The clip bounding box indicates the area of the context that
// is being requested for rendering. While not used here
// your app may require it to do scaling in other
// situations.
// CGRect rect = CGContextGetClipBoundingBox(context);
// Set and draw the background color of the entire layer
// The other option is to set the layer as opaque=NO;
// eliminate the following two lines of code
// and set the scroll view background color
CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
CGContextFillRect(context,self.bounds);
// draw a simple plus sign
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextBeginPath(context);
CGContextMoveToPoint(context,35,255);
CGContextAddLineToPoint(context,35,205);
CGContextAddLineToPoint(context,135,205);
CGContextAddLineToPoint(context,135,105);
CGContextAddLineToPoint(context,185,105);
CGContextAddLineToPoint(context,185,205);
CGContextAddLineToPoint(context,285,205);
CGContextAddLineToPoint(context,285,255);
CGContextAddLineToPoint(context,185,255);
CGContextAddLineToPoint(context,185,355);
CGContextAddLineToPoint(context,135,355);
CGContextAddLineToPoint(context,135,255);
CGContextAddLineToPoint(context,35,255);
CGContextClosePath(context);
// Stroke the simple shape
CGContextStrokePath(context);
}
五,Scrolling Using Paging Mode:
UIScrollView支持Paging模式,你需要设置pagingMode为YES。
contentSize属性需要设置为宽度= width*pages 高度=height*1。
额外地,scroll Indicator应该被禁用(使用showHorizontalIndicator和showVerticalIndicator=NO),因为在用户触摸屏幕时相对位置是不相关的,或者使用UIPageControl来显示。
一
个paging scroll
view的subviews可以通过两种方法配置:如果内容是小的,你可以一次性绘制所有的内容到一个视图中,这个视图的大小就是scroll
view的contentSize大小。当然这是最初的实现方法,当处理大的内容区域时,或页面内容需要时间绘制时,这种方法是不够效率的。
上述两种情况以及累死情形,你应该使用多视图来展示内容,每个page一个view。
假定在一个paging scroll view里有很多很多pages,可以只通过3个view实例来得到:当scroll view controller被初始化后,所有的3个视图被创建和初始化。一般这些视图是UIView的子视图。
因为用户滚动内容,要确定什么时候页需要被重新配置,scroll view需要一个代理实现 scrollViewDidScroll:方法。这个方法需要跟踪contentOffset属性,并且在其超过中间的点的时候,视图应该被重新配置。
如果绘制页面内容是耗时的操作,你的应该应该增加额外的视图到视图池,指示这些。
六,Nesting Scroll Views:
标签:
原文地址:http://www.cnblogs.com/Cheetah-yang/p/4657748.html