UIScrollView的使用大全

转载自 http://blog.csdn.net/ch_soft/article/details/6947695

 

UIScrollView 原理详解


ScrollView

 

       UIScrollView

     UIScrollView为了显示多于一个屏幕的内容或者超过你能放在内存中的内容。

                 Scroll View为你处理缩小放大手势,UIScrollView实现了这些手势,并且替你处理对于它们的探测和回应。其中需要注意的子类是UITableView以及UITextView(用来显示大量的文字)。还有一个UIWebView,尽管那不是UIScrollView的直接子类,它适用UIScrollView去显示网页内容

        contentsize是内容的宽和高,contentsize.width是内容的宽度,contentsize.heght是高度,contentsize是UIScrollView的一个属性,它是一个CGSize,是由核心图形所定义的架构,那定义了你可以滚轴内容的宽度和高度,你也可以添加可以上下滚动的额外区域。第一种方法是你可以通过添加内容的大小来完成。另外一个比较动态的选择是UIScrollView的另一个属性contentInset,contentInset增加你在contentsize中指定的内容能够滚动的上下左右区域数量contentInset.top以及contentInset.buttom分别表示上面和下面的距离。

           在滚轴视图中,有一个叫做ContentOffset的属性跟踪UIScrollView的具体位置,你能够自己获取和设置它,ContentOffset是你当前可视内容在滚轴视图边界的左上角那个点。如图:

           可以看出,ContentOffset内容中的那个点不是从contentInset的左上角开始的,而是内容的左上角,此时的ContentOffset是正值,但有时也是负值,如下图所示:

使用一个ScrollView

     创建一个UIScrollView

             CGRectframe = CGRectMake( 0, 0, 200, 200);

              scrollView= [[UIScrollView alloc] initWithFrame: frame];

    添加子视图(框架可以超过scroll view的边界)

            frame= CGRectMake( 0, 0, 500, 500);

            myImageView= [[UIImageView alloc] initWithFrame: frame];

           [scrollViewaddSubview:myImageView];

    设置内容尺寸

           scrollView.contentSize= CGSize(500,500);

 

扩展Scroll View 的行为

      应用程序通常需要知道有关的滚图的事件

            scrolloffset改变的时候

           拖动开始和结束

            减速的开始和结束

 

通过子类化扩展Scroll View 的行为

        创建一个子类

        重写一些功能并改变行为

        关于这种方式的争议

               应用程序的逻辑和行为变成了视图本身的一部分,就像,你可能有一些定制的滚轴逻辑,,在那你只在意一个视图控制,但你想在不同地方重复使用你的滚轴视图,如果你必须为每个都子类化,你最后会有很多不同的滚轴视图子类以及在视图中的特定应用逻辑。

              编写很多子类是很沉闷的事情,你最后会有很多无法重复使用的单独视图,而MVC的视图部分的一个重点是视图是可以在不同的控制器和不同的模式之中重复使用的,如果我们把所有逻辑都放在视图中,它减少了可复用性。

              你的代码变得很牢固地配对在一起,它实际上变成了超类的一部分,你无法从UIScrollView中析取它,之后用其它东西代替,如果它在你控制器中且为控制器的一部分,在之后更容易改变它工作的方式和重新安排你应用程序的一些部分。

 

通过委派来扩展Scroll View 的行为(常用的)

         委派是一个单独的对象,协议,定义了委派会实现的一系列功能的Objective-C协议,它创建了一系列很清晰的撤销点,在那里你能定制行为和外观。它在这些对象之间保持了松散的配对,视图本身与视图控制器或任何其它的控制器对象,委派不是滚轴视图的直接子类,它比起牢固配对的子类更加的松散。


 

 

 

首先引用别人分析一篇不错的文章,同时也感谢这位朋友的分享:http://www.cocoachina.com/iphonedev/sdk/2010/1224/2503.html   

  在滚动过程当中,其实是在修改原点坐标。当手指触摸后, scroll view会暂时拦截触摸事件,使用一个计时器。假如在计时器到点后没有发生手指移动事件,那么 scroll view 发送 tracking events 到被点击的 subview。假如在计时器到点前发生了移动事件,那么 scroll view 取消 tracking 自己发生滚动。

    子类可以重载

touchesShouldBegin:withEvent:inContentView: 决定自己是否接收 touch 事件
pagingEnabled:当值是 YES 会自动滚动到 subview 的边界,默认是NO
touchesShouldCancelInContentView: 开始发送 tracking messages 消息给 subview 的时候调用这个方法,决定是否发送 tracking messages 消息到subview。假如返回 NO,发送。YES 则不发送。
假如 canCancelContentTouches属性是NO,则不调用这个方法来影响如何处理滚动手势。

    scroll view 还处理缩放和平移手势,要实现缩放和平移,必须实现委托 viewForZoomingInScrollView:、scrollViewDidEndZooming:withView:atScale:
两个方法。另外 maximumZoomScale和minimumZoomScale 两个属性要不一样。

几个属性介绍

tracking
当 touch 后还没有拖动的时候值是YES,否则NO

zoomBouncing
当内容放大到最大或者最小的时候值是 YES,否则 NO

zooming
当正在缩放的时候值是 YES,否则 NO

decelerating
当滚动后,手指放开但是还在继续滚动中。这个时候是 YES,其它时候是 NO

decelerationRate
设置手指放开后的减速率

maximumZoomScale
一个浮点数,表示能放最大的倍数

minimumZoomScale 
一个浮点数,表示能缩最小的倍数

pagingEnabled
当值是 YES 会自动滚动到 subview 的边界。默认是NO

scrollEnabled
决定是否可以滚动

delaysContentTouches
是个布尔值,当值是 YES 的时候,用户触碰开始,scroll view要延迟一会,看看是否用户有意图滚动。假如滚动了,那么捕捉 touch-down 事件,否则就不捕捉。假如值是NO,当用户触碰, scroll view 会立即触发 touchesShouldBegin:withEvent:inContentView:,默认是 YES

canCancelContentTouches
当值是 YES 的时候,用户触碰后,然后在一定时间内没有移动,scrollView 发送 tracking events,然后用户移动手指足够长度触发滚动事件,这个时候,scrollView 发送了 touchesCancelled:withEvent: 到 subview,然后 scroView 开始滚动。假如值是 NO,scrollView 发送 tracking events 后,就算用户移动手指,scrollView 也不会滚动。

contentSize
里面内容的大小,也就是可以滚动的大小,默认是0,没有滚动效果。

showsHorizontalScrollIndicator
滚动时是否显示水平滚动条

showsVerticalScrollIndicator
滚动时是否显示垂直滚动条

bounces
默认是 yes,就是滚动超过边界会反弹有反弹回来的效果。假如是 NO,那么滚动到达边界会立刻停止。

bouncesZoom
和 bounces 类似,区别在于:这个效果反映在缩放上面,假如缩放超过最大缩放,那么会反弹效果;假如是 NO,则到达最大或者最小的时候立即停止。

directionalLockEnabled
默认是 NO,可以在垂直和水平方向同时运动。当值是 YES 时,假如一开始是垂直或者是水平运动,那么接下来会锁定另外一个方向的滚动。 假如一开始是对角方向滚动,则不会禁止某个方向

indicatorStyle
滚动条的样式,基本只是设置颜色。总共3个颜色:默认、黑、白

scrollIndicatorInsets
设置滚动条的位置

最后加上,我刚定的一个例子,可以缩放,及对使用的代理方法加了注释

 

 

 

//  ScrollViewViewController.m

//  ScrollView

//

//  Created by ch_soft on 11-11-8.

//  Copyright 2011年 __MyCompanyName__. All rights reserved.

//

 

#import"ScrollViewViewController.h"

#import"CustomA.h"

#import"CustomB.h"

 

@implementation ScrollViewViewController

 

- (void)didReceiveMemoryWarning

{

   // Releases the view if it doesn't have a superview.

    [superdidReceiveMemoryWarning];

    

   // Release any cached data, images, etc that aren't in use.

}

 

#pragma mark - View lifecycle

 

 

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad

{

   scrollview =[[UIScrollViewalloc]initWithFrame:CGRectMake(50,0,200,400)];

    scrollview.contentSize=CGSizeMake(400,400);

   scrollview.backgroundColor=[UIColororangeColor];

   scrollview.pagingEnabled=YES;//是否自己动适应

    

   viewA=[[CustomAalloc]initWithFrame:CGRectMake(50,0,100,400)];

   viewA.backgroundColor=[UIColorblueColor];

    [scrollviewaddSubview:viewA];

    [viewArelease];

    

    CustomB * viewB=[[CustomB alloc] initWithFrame:CGRectMake(250,0,100,400)];

    viewB.backgroundColor=[UIColoryellowColor];

    [scrollviewaddSubview:viewB];

    [viewB release];

    

    [self.viewaddSubview:scrollview];

   scrollview.maximumZoomScale=2.0;

   scrollview.minimumZoomScale=0.5;

//    scrollview.decelerationRate=1;

   scrollview.delegate=self;

   //canCancelContentTouches:YES-移动手指足够长度触发滚动事件,NO-scrollView发送 tracking events 后,就算用户移动手指,scrollView也不会滚动。

   scrollview.canCancelContentTouches=NO;

    

    //当值是 YES的时候,用户触碰开始.要延迟一会,看看是否用户有意图滚动。假如滚动了,那么捕捉 touch-down事件,否则就不捕捉。假如值是NO,当用户触碰, scroll view会立即触发

   scrollview.delaysContentTouches=YES;

    [scrollviewrelease];

    [superviewDidLoad];

}

 

 

#pragma mark UIScrollViewDelegate

//只要滚动了就会触发

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;   

{

//    NSLog(@" scrollViewDidScroll");

    NSLog(@"ContentOffset  x is  %f,yis %f",scrollView.contentOffset.x,scrollView.contentOffset.y);

}

//开始拖拽视图

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewWillBeginDragging");

}

//完成拖拽

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 

{

   NSLog(@"scrollViewDidEndDragging");

}

//将开始降速时

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewWillBeginDecelerating");

}

 

//减速停止了时执行,手触摸时执行执行

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewDidEndDecelerating");

}

//滚动动画停止时执行,代码改变时出发,也就是setContentOffset改变时

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;

{

   NSLog(@"scrollViewDidEndScrollingAnimation");

}

//设置放大缩小的视图,要是uiscrollview的subview

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;   

{

   NSLog(@"viewForZoomingInScrollView");

    return viewA;

}

//完成放大缩小时调用

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale; 

{

    viewA.frame=CGRectMake(50,0,100,400);

   NSLog(@"scale between minimum and maximum. called after any 'bounce' animations");

}// scale between minimum and maximum. called after any 'bounce' animations

 

//如果你不是完全滚动到滚轴视图的顶部,你可以轻点状态栏,那个可视的滚轴视图会一直滚动到顶部,那是默认行为,你可以通过该方法返回NO来关闭它

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;   

{

    NSLog(@"scrollViewShouldScrollToTop");

   returnYES;

}

 

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;     

{

    NSLog(@"scrollViewDidScrollToTop");

}

 

 

 

- (void)viewDidUnload

{

    [super viewDidUnload];

   // Release any retained subviews of the main view.

   // e.g. self.myOutlet = nil;

}

 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

   // Return YES for supported orientations

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

 

@end

 

完毕,如发现在有新的内容再更新

 

 

最后加上,我刚定的一个例子,可以缩放,及对使用的代理方法加了注释

 

 

 

//  ScrollViewViewController.m

//  ScrollView

//

//  Created by ch_soft on 11-11-8.

//  Copyright 2011年 __MyCompanyName__. All rights reserved.

//

 

#import"ScrollViewViewController.h"

#import"CustomA.h"

#import"CustomB.h"

 

@implementation ScrollViewViewController

 

- (void)didReceiveMemoryWarning

{

   // Releases the view if it doesn't have a superview.

    [superdidReceiveMemoryWarning];

    

   // Release any cached data, images, etc that aren't in use.

}

 

#pragma mark - View lifecycle

 

 

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.

- (void)viewDidLoad

{

   scrollview =[[UIScrollViewalloc]initWithFrame:CGRectMake(50,0,200,400)];

    scrollview.contentSize=CGSizeMake(400,400);

   scrollview.backgroundColor=[UIColororangeColor];

   scrollview.pagingEnabled=YES;//是否自己动适应

    

   viewA=[[CustomAalloc]initWithFrame:CGRectMake(50,0,100,400)];

   viewA.backgroundColor=[UIColorblueColor];

    [scrollviewaddSubview:viewA];

    [viewArelease];

    

    CustomB * viewB=[[CustomB alloc] initWithFrame:CGRectMake(250,0,100,400)];

    viewB.backgroundColor=[UIColoryellowColor];

    [scrollviewaddSubview:viewB];

    [viewB release];

    

    [self.viewaddSubview:scrollview];

   scrollview.maximumZoomScale=2.0;

   scrollview.minimumZoomScale=0.5;

//    scrollview.decelerationRate=1;

   scrollview.delegate=self;

   //canCancelContentTouches:YES-移动手指足够长度触发滚动事件,NO-scrollView发送 tracking events 后,就算用户移动手指,scrollView也不会滚动。

   scrollview.canCancelContentTouches=NO;

    

    //当值是 YES的时候,用户触碰开始.要延迟一会,看看是否用户有意图滚动。假如滚动了,那么捕捉 touch-down事件,否则就不捕捉。假如值是NO,当用户触碰, scroll view会立即触发

   scrollview.delaysContentTouches=YES;

    [scrollviewrelease];

    [superviewDidLoad];

}

 

 

#pragma mark UIScrollViewDelegate

//只要滚动了就会触发

- (void)scrollViewDidScroll:(UIScrollView *)scrollView;   

{

//    NSLog(@" scrollViewDidScroll");

    NSLog(@"ContentOffset  x is  %f,yis %f",scrollView.contentOffset.x,scrollView.contentOffset.y);

}

//开始拖拽视图

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewWillBeginDragging");

}

//完成拖拽

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 

{

   NSLog(@"scrollViewDidEndDragging");

}

//将开始降速时

- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewWillBeginDecelerating");

}

 

//减速停止了时执行,手触摸时执行执行

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;   

{

   NSLog(@"scrollViewDidEndDecelerating");

}

//滚动动画停止时执行,代码改变时出发,也就是setContentOffset改变时

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;

{

   NSLog(@"scrollViewDidEndScrollingAnimation");

}

//设置放大缩小的视图,要是uiscrollview的subview

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;   

{

   NSLog(@"viewForZoomingInScrollView");

    return viewA;

}

//完成放大缩小时调用

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale; 

{

    viewA.frame=CGRectMake(50,0,100,400);

   NSLog(@"scale between minimum and maximum. called after any 'bounce' animations");

}// scale between minimum and maximum. called after any 'bounce' animations

 

//如果你不是完全滚动到滚轴视图的顶部,你可以轻点状态栏,那个可视的滚轴视图会一直滚动到顶部,那是默认行为,你可以通过该方法返回NO来关闭它

- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;   

{

    NSLog(@"scrollViewShouldScrollToTop");

   returnYES;

}

 

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;     

{

    NSLog(@"scrollViewDidScrollToTop");

}

 

 

 

- (void)viewDidUnload

{

    [super viewDidUnload];

   // Release any retained subviews of the main view.

   // e.g. self.myOutlet = nil;

}

 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

{

   // Return YES for supported orientations

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

 

@end

 

完毕,如发现在有新的内容再更新

 

 

UIScrollView基本用法和代理方法

- (void)viewDidLoad
{
    [super viewDidLoad];
     
    scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)];
    scrollView.backgroundColor = [UIColor redColor];
    // 是否支持滑动最顶端
//    scrollView.scrollsToTop = NO;
    scrollView.delegate = self;
    // 设置内容大小
    scrollView.contentSize = CGSizeMake(320, 460*10);
    // 是否反弹
//    scrollView.bounces = NO;
    // 是否分页
//    scrollView.pagingEnabled = YES;
    // 是否滚动
//    scrollView.scrollEnabled = NO;
//    scrollView.showsHorizontalScrollIndicator = NO;
    // 设置indicator风格
//    scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
    // 设置内容的边缘和Indicators边缘
//    scrollView.contentInset = UIEdgeInsetsMake(0, 50, 50, 0);
//    scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 50, 0, 0);
    // 提示用户,Indicators flash
    [scrollView flashScrollIndicators];
    // 是否同时运动,lock
    scrollView.directionalLockEnabled = YES;
    [self.view addSubview:scrollView];
     
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, 320, 40)];
    label.backgroundColor = [UIColor yellowColor];
    label.text = @"学习scrolleview";
    [scrollView addSubview:label];
    [label release];
}
 
#pragma mark -
/*
// 返回一个放大或者缩小的视图
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
     
}
// 开始放大或者缩小
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:
(UIView *)view
{
     
}
 
// 缩放结束时
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
     
}
  
// 视图已经放大或缩小
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
NSLog(@"scrollViewDidScrollToTop");
}
 */
 
// 是否支持滑动至顶部
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView
{
    return YES;
}
 
// 滑动到顶部时调用该方法
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView
{
    NSLog(@"scrollViewDidScrollToTop");
}
 
// scrollView 已经滑动
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSLog(@"scrollViewDidScroll");
}
 
// scrollView 开始拖动
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    NSLog(@"scrollViewWillBeginDragging");
}
 
// scrollView 结束拖动
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    NSLog(@"scrollViewDidEndDragging");
}
 
// scrollView 开始减速(以下两个方法注意与以上两个方法加以区别)
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
    NSLog(@"scrollViewWillBeginDecelerating");
}
 
// scrollview 减速停止
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
   NSLog(@"scrollViewDidEndDecelerating");
}
 
 

UIScrollView可以用于显示多于一个屏幕的内容,超出屏幕范围的内容可以通过滑动进行查看

方法/步骤

  1.  

    常见属性

    CGSize contentSize :设置UIScrollView的滚动范围

    CGPoint contentOffset :UIScrollView当前滚动的位置

    UIEdgeInsets contentInset :这个属性可以在四周增加滚动范围

    iOS程序-UIScrollView的基本使用
  2.  

    其他属性

    BOOL bounces 是否有弹簧效果

    BOOL scrollEnabled 是否能滚动

    BOOL showsHorizontalScrollIndicator 是否显示水平方向的滚动条

    BOOL showsVerticalScrollIndicator     是否显示垂直方向的滚动条

    UIScrollViewIndicatorStyle indicatorStyle  设定滚动条的样式

    BOOL dragging 是否正在被拖拽

    BOOL tracking  当touch后还没有拖动的时候值是YES,否则NO

    BOOL decelerating 是否正在减速

    BOOL zooming 是否正在缩放

  3.  

    手势缩放

    设置UIScrollView的id<UISCrollViewDelegate> delegate代理对象

    设置minimumZoomScale :缩小的最小比例

    设置maximumZoomScale :放大的最大比例

    让代理对象实现下面的方法,返回需要缩放的视图控件

    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView

    跟缩放相关的常用方法还有

    正在缩放的时候调用

    -(void)scrollViewDidZoom:(UIScrollView *)scrollView

    缩放完毕的时候调用

    -(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale

    iOS程序-UIScrollView的基本使用
  4.  

    分页效果

    设置pagingEnabled=YES即可,UIScrollView会被分割成多个独立页面,用户的滚动体验则变成了页面翻转

    一般会配合UIPageControl增强分页效果,UIPageControl常用属性:

    NSInteger numberOfPages : 总页数

    NSInteger currentPage : 当前的页码

    BOOL hidesForSinglePage : 当只有一页的时候,是否要隐藏视图

    监听UIPageControl的页面改变:

    // 添加监听器

    [pageControl addTarget:self action:@selector(pageChange:) 

    forControlEvents:UIControlEventValueChanged];

    // 监听方法

    - (void)pageChange:(UIPageControl *)pageControl 

    {  

    }

  5.  

    图片全屏浏览

    iOS程序-UIScrollView的基本使用

     

     

    UIScrollView的属性总结
    属性 作用
    CGPoint contentOffSet 监控目前滚动的位置
    CGSize contentSize 滚动范围的大小
    UIEdgeInsets contentInset 视图在scrollView中的位置
    id<UIScrollerViewDelegate>
    delegate
    设置协议
    BOOL directionalLockEnabled 指定控件是否只能在一个方向上滚动
    BOOL bounces 控制控件遇到边框是否反弹
    BOOL alwaysBounceVertical 控制垂直方向遇到边框是否反弹
    BOOL alwaysBounceHorizontal 控制水平方向遇到边框是否反弹
    BOOL pagingEnabled 控制控件是否整页翻动
    BOOL scrollEnabled 控制控件是否能滚动
    BOOL showsHorizontalScrollIndicator 控制是否显示水平方向的滚动条
    BOOL
    showsVerticalScrollIndicator
    控制是否显示垂直方向的滚动条
    UIEdgeInsets scrollIndicatorInsets 指定滚动条在scrollerView中的位置
    UIScrollViewIndicatorStyle
    indicatorStyle
    设定滚动条的样式
    float decelerationRate 改变scrollerView的减速点位置
    BOOL tracking 监控当前目标是否正在被跟踪
    BOOL dragging 监控当前目标是否正在被拖拽
    BOOL decelerating 监控当前目标是否正在减速
    BOOL delaysContentTouches 控制视图是否延时调用开始滚动的方法
    BOOL canCancelContentTouches 控制控件是否接触取消touch的事件
    float minimumZoomScale 缩小的最小比例
    float maximumZoomScale 放大的最大比例
    float zoomScale 设置变化比例
    BOOL bouncesZoom 控制缩放的时候是否会反弹
    BOOL zooming 判断控件的大小是否正在改变
    BOOL zoomBouncing 判断是否正在进行缩放反弹
    BOOL scrollsToTop 控制控件滚动到顶部

    这里把UIScrollView的几个要点总结下:

    从你的手指touch屏幕开始,scrollView开始一个timer,如果:

    1.  150ms内如果你的手指没有任何动作,消息就会传给subView。

    2.  150ms内手指有明显的滑动(一个swipe动作),scrollView就会滚动,消息不会传给subView,这里就是产生问题二的原因。

    3. 150ms内手指没有滑动,scrollView将消息传给subView,但是之后手指开始滑动,scrollView传送touchesCancelled消息给subView,然后开始滚动。

    观察下tableView的情况,你先按住一个cell,cell开始高亮,手不要放开,开始滑动,tableView开始滚动,高亮取消。

     

    delaysContentTouches的作用:

    这个标志默认是YES,使用上面的150ms的timer,如果设置为NO,touch事件立即传递给subView,不会有150ms的等待。

     

    cancelsTouches的作用:

    这个标准默认为YES,如果设置为NO,这消息一旦传递给subView,这scroll事件不会再发生。

     

     
     

    我是Mike Ash的Let’s Build…系列文章的忠实粉丝,在这一系列文章中他从头设计Cocoa的控件来解释他们的工作原理。在这里我要做一点类似的事情,用几行代码来实现我自己的滚动试图。不过首先,让我们先来了解一下UIKit中的坐标系是怎么工作的。如果你只对滚动试图的代码实现感兴趣可以放心跳过下一小节。UIKit坐标系每一个View都定义了他自己的坐标系统。如下图所示,x轴指向右方,y轴指向下方:

    A standard x/y coordinate system with the x-axis pointing right and the y-axis pointing down

    注意这个逻辑坐标系并不关注包含在其中View的宽度和高度。整个坐标系没有边界向四周无限延伸.我们在坐标系中放置四个子View。每一次色块代表一个View:

     

    Four rectangles with different colors and sizes placed at different coordinates in the coordinate system

    添加View的代码实现如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
    redView.backgroundColor = [UIColor colorWithRed:0.815 green:0.007
        blue:0.105 alpha:1];
     
    UIView *greenView = [[UIView alloc] initWithFrame:CGRectMake(150, 160, 150, 200)];
    greenView.backgroundColor = [UIColor colorWithRed:0.494 green:0.827
        blue:0.129 alpha:1];
     
    UIView *blueView = [[UIView alloc] initWithFrame:CGRectMake(40, 400, 200, 150)];
    blueView.backgroundColor = [UIColor colorWithRed:0.29 green:0.564
        blue:0.886 alpha:1];
     
    UIView *yellowView = [[UIView alloc] initWithFrame:CGRectMake(100, 600, 180, 150)];
    yellowView.backgroundColor = [UIColor colorWithRed:0.972 green:0.905
        blue:0.109 alpha:1];
     
    [mainView addSubview:redView];
    [mainView addSubview:greenView];
    [mainView addSubview:blueView];
    [mainView addSubview:yellowView];

    bounds

    Apple关于UIView的文档中是这样描述bounds属性的:

    bounds矩形…描述了该视图在其自身坐标系中的位置和大小。

    一个View可以被看作是定义在其所在坐标系平面上的一扇窗户或者说是一个矩形的可视区域。View的边界表明了这个矩形可视区域的位置和大小。

    假设我们的View宽320像素,高480像素,原点在(0,0)。那么这个View就变成了整个坐标系平面的观察口,它展示的只是整个平面的一小部分。位于该View边界外的区域依然存在,只是被隐藏起来了。

     

    A viewport of 320 by 480 points provides a viewport into the coordinate system. Some of the rectangles are inside the viewport and some outside.

    一个View提供了其所在平面的一个观察口。View的bounds矩形描述了这个可是区域的位置和大小。

    Frame

    接下来我们来试着修改bounds的原点坐标:

    1
    2
    3
    CGRect bounds = mainView.bounds;
    bounds.origin = CGPointMake(0, 100);
    mainView.bounds = bounds;

    当我们把bound原点设为(0,100)后,整个画面看起来就像这样:

    The viewport has moved down by 100 points, making a different area of the coordinate system visible.

    修改bounds的原点就相当与在平面上移动这个可视区域。

    看起来好像是这个View向下移动了100像素,在这个View自己的坐标系中这确实没错。不过这个View真正位于屏幕上的位置(更准确的说在其父View上的位置)其实没有改变,因为这是由View的frame属性决定的,它并没有改变:

    frame矩形…定义了这个View在其父View坐标系中的位置和大小。

     

    由于View的位置是相对固定的,你可以把整个坐标平面想象成我们可以上下拖动的透明幕布,把这个View想象成我们观察坐标平面的窗口。调整View的Bounds属性就相当于拖动这个幕布,那么下方的内容就能在我们View中被观察到:

    Since the view’s position is fixed (from its own perspective), think of the coordinate system plane as a piece of transparent film we can drag around, and of the view as a fixed window we are looking through. Adjusting the bounds’s origin is equivalent to moving the transparent film such that another part of it becomes visible through the view:

    Animation illustrating the movement of the coordinate system caused by a change of the bounds origin

    修改bounds的原点坐标也相当于把整个坐标系向上拖动,因为View的frame没由变过,所以它相对于父View的位置没有变化过。

    其实这就是UIScrollView滑动时所发生的事情。注意从一个用户的角度来看,他以为时这个View中的子View在移动,其实他们的在坐标系中位置(他们的frame)没有发生过变化。

     

    打造你的UIScrollView

    一个scroll view并不需要其中子View的坐标来使他们滚动。唯一要做的就是改变他的bounds属性。知道了这一点,实现一个简单的scroll view就没什么困难了。我们用一个gesture recognizer来识别用户的拖动操作,根据用户拖动的偏移量来改变bounds的原点:

    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
    // CustomScrollView.h
    @import UIKit;
     
    @interface CustomScrollView : UIView
     
    @property (nonatomic) CGSize contentSize;
     
    @end
     
    // CustomScrollView.m
    #import "CustomScrollView.h"
     
    @implementation CustomScrollView
     
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self == nil) {
            return nil;
        }
        UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc]
            initWithTarget:self action:@selector(handlePanGesture:)];
        [self addGestureRecognizer:gestureRecognizer];
        return self;
    }
     
    - (void)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer
    {
        CGPoint translation = [gestureRecognizer translationInView:self];
        CGRect bounds = self.bounds;
     
        // Translate the view's bounds, but do not permit values that would violate contentSize
        CGFloat newBoundsOriginX = bounds.origin.x - translation.x;
        CGFloat minBoundsOriginX = 0.0;
        CGFloat maxBoundsOriginX = self.contentSize.width - bounds.size.width;
        bounds.origin.x = fmax(minBoundsOriginX, fmin(newBoundsOriginX, maxBoundsOriginX));
     
        CGFloat newBoundsOriginY = bounds.origin.y - translation.y;
        CGFloat minBoundsOriginY = 0.0;
        CGFloat maxBoundsOriginY = self.contentSize.height - bounds.size.height;
        bounds.origin.y = fmax(minBoundsOriginY, fmin(newBoundsOriginY, maxBoundsOriginY));
     
        self.bounds = bounds;
        [gestureRecognizer setTranslation:CGPointZero inView:self];
    }
     
    @end

    和真正的UIScrollView一样,我们的类也有一个contentSize属性,你必须从外部来设置这个值来指定可以滚动的区域,当我们改变bounds的大小时我们要确保设置的值是有效的。

    结果:

    Animated GIF showing our custom scroll view implementation

    我们的scroll view已经能够工作了,不过还缺少动量滚动,反弹效果还有滚动提示符。

    总结

    感谢UIKit的坐标系统特性,使我们之花了30几行代码就能重现UIScrollView的精华,当然真正的UIScrollView要比我们所做的复杂的多,反弹效果,动量滚动,放大试图,还有代理方法,这些特性我们没有在这里涉及到。

    更新 5/ 2, 2014: 本文的代码在https://github.com/ole/CustomScrollView。

    更新 5/ 8, 2014:

    1.坐标系并非无限延伸的。坐标系的范围由CGFloat的长度来决定,根据32位和64位系统有所不同,通常来讲这是一个很大的值。

    2.事实上,除非你设置clipToBounds == YES,所有子View超出的部分其实仍然是可见的。只是View不会再去检测超出部分的触摸事件而已。

    关于作者: 袁欣

     

     

     

     

     

     

    [iOS]通过UIScrollView和UIPageControl实现滑动切换的效果
    2014-07-16      0 个评论    来源:汪海的实验室   
    收藏    我要投稿

    UIPageControl是自带的控件,可以查看官方文档,下载官方示例学习。

    如果对Xcode自带的文档不熟悉可以参见:苹果Xcode帮助文档阅读指南

    接下来是我学习笔记,使用Storyboard实现滑动切换的效果。

     

    -----------------------------------------------------------------------------

     

    新建一个项目,拖上一个UIScrollView和UIPageControl,并且建立关联:

    \

     

    新建一个ContentViewController,作为页面切换的内容视图:

    \

     


    <喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD48cD7Ssr7NysfLtaOstbG7rLavxsHEu8fQu7u1xMqxuvKjrMbkyrW+zcrHtuC49kNvbnRlbnRWaWV3Q29udHJvbGxlctTax9C7u6GjPC9wPjxwPjxiciAvPjwvcD48cD67+bG+veG5ucrHo7o8L3A+PHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20140716/20140716085249107.png" alt="\" />

    在主页面,我们首先初始化一些设置:

     

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    	// Do any additional setup after loading the view, typically from a nib.
        
        // 初始化page control的内容
        _contentList = [NSArray arrayWithObjects:@"1",@"2",@"3",@"4", nil];
        
        
        // 一共有多少页
        NSUInteger numberPages = self.contentList.count;
        
        // 存储所有的controller
        NSMutableArray *controllers = [[NSMutableArray alloc] init];
        for (NSUInteger i = 0; i < numberPages; i++)
        {
    		[controllers addObject:[NSNull null]];
        }
        self.viewControllers = controllers;
        
        // 一个页面的宽度就是scrollview的宽度
        self.myScrollView.pagingEnabled = YES;  // 自动滚动到subview的边界
        self.myScrollView.contentSize =
        CGSizeMake(CGRectGetWidth(self.myScrollView.frame) * numberPages, CGRectGetHeight(self.myScrollView.frame));
        self.myScrollView.showsHorizontalScrollIndicator = NO;
        self.myScrollView.showsVerticalScrollIndicator = NO;
        self.myScrollView.scrollsToTop = NO;
        self.myScrollView.delegate = self;
        
        _numberOfPages = numberPages;
        _myPageControl.numberOfPages = numberPages;
        _currentPage = 0;
        
        
        [self loadScrollViewWithPage:0];
        [self loadScrollViewWithPage:1];
        
    }


     

     

     

     

     

    接下来,我们需要一个函数,来加载ContentView页面上的元素:

     

    // 加载ScrollView中的不同SubViewController
    - (void)loadScrollViewWithPage:(NSUInteger)page
    {
        if (page >= self.contentList.count)
            return;
        
        // replace the placeholder if necessary
        LContentViewController *controller = [self.viewControllers objectAtIndex:page];
        if ((NSNull *)controller == [NSNull null])
        {
            controller = [[LContentViewController alloc] init];
            [self.viewControllers replaceObjectAtIndex:page withObject:controller];
        }
        
        // add the controller's view to the scroll view
        if (controller.view.superview == nil)
        {
            CGRect frame = self.myScrollView.frame;
            frame.origin.x = CGRectGetWidth(frame) * page;
            frame.origin.y = 0;
            controller.view.frame = frame;
            [controller setLabel:[_contentList objectAtIndex:page]];
            [self.myScrollView addSubview:controller.view];
        }
    }
    

    然后先来处理一下PageControl的切换事件:

     

     

    - (void)gotoPage:(BOOL)animated
    {
        NSInteger page = self.myPageControl.currentPage;
        
        // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
        [self loadScrollViewWithPage:page - 1];
        [self loadScrollViewWithPage:page];
        [self loadScrollViewWithPage:page + 1];
        
    	// update the scroll view to the appropriate page
        CGRect bounds = self.myScrollView.bounds;
        bounds.origin.x = CGRectGetWidth(bounds) * page;
        bounds.origin.y = 0;
        [self.myScrollView scrollRectToVisible:bounds animated:animated];
    }
    
    // page control 选项修改监听
    - (IBAction)changePage:(id)sender
    {
        [self gotoPage:YES];    // YES = animate
    }

    滑动ScrollView的事件监听:

     

     

    // 滑动结束的事件监听
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
        // switch the indicator when more than 50% of the previous/next page is visible
        CGFloat pageWidth = CGRectGetWidth(self.myScrollView.frame);
        NSUInteger page = floor((self.myScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
        self.myPageControl.currentPage = page;
        NSLog(@"当前页面 = %d",page);
        // a possible optimization would be to unload the views+controllers which are no longer visible
        
        [self loadScrollViewWithPage:page - 1];
        [self loadScrollViewWithPage:page];
        [self loadScrollViewWithPage:page + 1];
    }
    


     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    UIScrollView 和UIPageControl 实现app启动滑动图

    发表于10个月前(2014-07-23 15:43)   阅读(4546) | 评论(3) 55人收藏此文章, 我要收藏
    13

    让“码农”快速实现财务自由,通联量化实验室激发你的投资潜力!

    摘要 为了吸引用户眼球或者传达更多的信息,启动app时,一般都会附上一个滑动图(只显示一次),下面为大家详解。

     

    一、使用NSUserDefaults 判断滑动图有没有出现过,加载滑动图

     

    NSUserDefaults 简介:

     

           NSUserDefaults可以将数据永久的保存在手机中,他是一个单例,用起来很方便,所以很适合用于保存简单的数据和为数据做标记。

    更多的关于NSUserDefaults的介绍请看:NSUserDefaults 简介

         你可以选择在AppDelegate.m中的didFinishLaunchingWithOptions 方法或者“初始界面”(加载的第一个viewController)的 viewDidLoad 方法中进行判断滑动图是否出现过,写上代码:

     

    1
    2
    3
    4
    5
    6
    7
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
     
    //判断滑动图是否出现过,第一次调用时“isScrollViewAppear” 这个key 对应的值是nil,会进入if中
        if (![@"YES" isEqualToString:[userDefaults objectForKey:@"isScrollViewAppear"]]) {
             
            [self showScrollView];//显示滑动图
        }

     

     

    二、初始化 UIScrollView 和  UIPageControl 为启动滑动图做准备

    UIScrollView : 带有滑动效果,在上面加入UIImageView再设置代理后,可以实现翻页显示图片的效果

    涉及的相关属性:

     

    contentSize : UIScrollView 显示的尺寸,这个按需求而设

     

    pagingEnabled : 是否支持一页一页的翻,设置成YES后,每一次滑动,翻动一页;

     

    bounces:是否支持反弹,这是一个动画效果,大家可以设置来看看,一般滑动图设置为NO;

     

    showsHorizontalScrollIndicator : 是否显示水平的滑动条

     

     

    UIPageControl:一般配合UIScrollView使用,指向UIScrollView当前所指的页数

     

    涉及的相关属性:

     

    numberOfPages:一共有几个点(几页),这个要设置得和滑动图的页数一样

     

     

    相关代码:

     

    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
    #pragma mark - 滑动图
     
    -(void) showScrollView{
     
        UIScrollView *_scrollView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
         
          //设置UIScrollView 的显示内容的尺寸,有n张图要显示,就设置 屏幕宽度*n ,这里假设要显示4张图
        _scrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width * 4, [UIScreen mainScreen].bounds.size.height);
         
        _scrollView.tag = 101;
         
        //设置翻页效果,不允许反弹,不显示水平滑动条,设置代理为自己
        _scrollView.pagingEnabled = YES;
        _scrollView.bounces = NO;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.delegate = self;
         
        //在UIScrollView 上加入 UIImageView
        for (int i = 0 ; i < 4; i ++) {
             
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width * i , 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
             
            //将要加载的图片放入imageView 中
            UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i+1]];
            imageView.image = image;
             
            [_scrollView addSubview:imageView];
        }
         
        //初始化 UIPageControl 和 _scrollView 显示在 同一个页面中
        UIPageControl *pageConteol = [[UIPageControl alloc] initWithFrame:CGRectMake(140, self.view.frame.size.height - 60, 50, 40)];
        pageConteol.numberOfPages = 4;//设置pageConteol 的page 和 _scrollView 上的图片一样多
        pageConteol.tag = 201;
         
        [self.view addSubview:_scrollView];
        [self.view addSubview: pageConteol];
    }

     

     

     

     

    三、实现UIScrollView的代理方法

     

    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 介绍:

     

           顾名思义,这是一个滑动后减速结束的方法,这里进行的是 UIPageControl 和 UIScrollView的配

     

    套使用、滑动图消失信息等:

     

    涉及到的相关属性:

     

    UIScrollView:

     

    contentOffset : UIScrollView 的偏移量(滑动的位置)

     

    UIPageControl:

     

    currentPage : UIPageControl 的当前页 

     

     

    相关代码:

     

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #pragma mark - UIScrollViewDelegate
     
    - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
         
        // 记录scrollView 的当前位置,因为已经设置了分页效果,所以:位置/屏幕大小 = 第几页
        int current = scrollView.contentOffset.x/[UIScreen mainScreen].bounds.size.width;
         
        //根据scrollView 的位置对page 的当前页赋值
        UIPageControl *page = (UIPageControl *)[self.view viewWithTag:201];
        page.currentPage = current;
         
        //当显示到最后一页时,让滑动图消失
        if (page.currentPage == 3) {
             
            //调用方法,使滑动图消失
            [self scrollViewDisappear];
        }
    }

     

     

    四、从屏幕上移除UIScrollView,并保存信息

         这里只需要将UIScrollView和UIPageControl 从主屏幕上移除就可以了,别忘了将启动信息保存到 NSUserDefaults 中,当然你可以设置一些动画效果,或者需要点击才能移除都可以,下面给出的代码是一个简单的动画效果:

    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    -(void)scrollViewDisappear{
     
        //拿到 view 中的 UIScrollView 和 UIPageControl
        UIScrollView *scrollView = (UIScrollView *)[self.view viewWithTag:101];
        UIPageControl *page = (UIPageControl *)[self.view viewWithTag:201];
     
        //设置滑动图消失的动画效果图
        [UIView animateWithDuration:3.0f animations:^{
             
            scrollView.center = CGPointMake(self.view.frame.size.width/2, 1.5 * self.view.frame.size.height);
             
        } completion:^(BOOL finished) {
             
            [scrollView removeFromSuperview];
            [page removeFromSuperview];
        }];
         
        //将滑动图启动过的信息保存到 NSUserDefaults 中,使得第二次不运行滑动图
        NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
        [userDefaults setObject:@"YES" forKey:@"isScrollViewAppear"];
    }

     

     

    这个滑动图代码稍作修改,可以添加定时翻页,相册浏览,点击连接到相应的事件等,原理都是一样的。

     

     

     

posted @ 2015-05-21 15:42  苏苏zhao  阅读(446)  评论(0)    收藏  举报