ScrollView

http://www.cnblogs.com/dyf520/p/3805297.html

一,创建和配置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字段。如下图所示:

 

Scroll View Programming Guide for iOS--1 - supershll - 记忆里

 

上 图指定了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时,alwaysBounceVerticalalwaysBounceHorizontal属性不影响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属性,并且在其超过中间的点的时候,视图应该被重新配置。
如果绘制页面内容是耗时的操作,你的应该应该增加额外的视图到视图池,指示这些。

 
 
 
原文地址:https://www.cnblogs.com/Cheetah-yang/p/4657748.html