iOS开发系列--无限循环的图片浏览器
Posted 灯火阑处
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发系列--无限循环的图片浏览器相关的知识,希望对你有一定的参考价值。
--UIKit之UIScrollView
概述
UIKit框架中有大量的控件供开发者使用,在ios开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件。在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通。今天我们主要来看一下UIScrollView的内容
UIView
在熟悉UIScrollView之前很有必要说一下UIView的内容。在上一篇文章也简单的对UIView进行了介绍,但是由于那篇文章的主要内容是给大家一个iOS开发的总体印象,因此并没有系统的介绍。另外由于UIScrollView的父类是UIView,所有在讨论UIScrollView之前也很有必要把UIView的知识给补充上,这样大家在使用UIScrollView的某些方法时也不至于无从下手。
既然UIView是所有控件的父类,那么对于一些常用的方法我们很有必要弄清楚,其实在Xcode中要了解一个类有哪些属性和方法特别简单,只要按住apple键点击类名就可以定位到这个类中查看相关定义(在日后的开发中我们会经常这么来做,毕竟要记住iOS开发中所有的API是不现实的,有些API我们可以通过这种方法来查找),例如我们可以查看这个类的内容:
当然UIView的定义文件(.h文件)也是相当长的,我们如果全部截图也没有意义。这里列出常用的属性和方法。
属性 | 说明 |
@property(nonatomic) CGRect frame; | 控件的位置和大小,所有的控件必须指定这个属性,否则即使有控件也无法显示 |
@property(nonatomic) CGRect bounds; | 当前控件位置和大小,但是和frame不同的是它的位置是确定的(0,0) |
@property(nonatomic) CGPoint center; | 控件的中心位置,一般用户进行控件定位 |
@property(nonatomic) CGAffineTransform transform; | 控件矩阵变化,包括平移、缩放、旋转,默认为CGAffineTransformIdentity |
@property(nonatomic) UIViewAutoresizing autoresizingMask; | 控件旋转时大小自动伸缩,默认为UIViewAutoresizingNone |
@property(nonatomic,readonly) UIView *superview; | 当前控件的父控件 |
@property(nonatomic,readonly,copy) NSArray *subviews; | 当前控件的所有一级子控件,注意其子控件的子控件并不包括在内 |
@property(nonatomic,getter=isHidden) BOOL hidden; | 是否隐藏,默认为NO |
@property(nonatomic) UIViewContentMode contentMode; | 内容模式,主要用于指定控件内容(注意不是子控件)如何填充,一般UIImageView经常使用,默认为UIViewContentModeScaleToFill |
@property(nonatomic) NSInteger tag; | 控件的标示,可以存储一些和当前控件有关的信息(但是注意只能是整形),默认为0 |
方法 | 说明 |
- (void)addSubview:(UIView *)view; | 添加子控件 |
- (void)removeFromSuperview; | 从父控件中移除当前控件 |
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index; | 在指定位置插入子控件 |
+ (void)beginAnimations:(NSString *)animationID context:(void *)context; | 开始一段动画 |
+ (void)commitAnimations; | 结束一段动画,注意在开始和结束之间如果控件的某些属性发生变化iOS将以动画方式进行改变 |
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0); | 以block的形式执行一段动画,注意这个方法有几种相关的重载 |
- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer NS_AVAILABLE_IOS(3_2); | 添加手势操作 |
- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer NS_AVAILABLE_IOS(3_2); | 移除手势操作 |
注意上面所有的位置属性都是相对于其父控件而言(不是相对于屏幕而言),多数属性比较简单这里不再详细解释,我们重点解释一下autoresizingMask、transform属性。
autoresizingMask
autoresizingMask这个属性一般我们进行屏幕旋转的时候经常用到,它的值是一个枚举类型:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) UIViewAutoresizingNone = 0, //不进行自动调整 UIViewAutoresizingFlexibleLeftMargin = 1 << 0, //自动调整与superview左侧距离,右侧距离保持不变 UIViewAutoresizingFlexibleWidth = 1 << 1, //自动调整控件自身宽度,保证与superview左右距离不变 UIViewAutoresizingFlexibleRightMargin = 1 << 2, //自动调整与superview右侧距离,左侧距离保持不变 UIViewAutoresizingFlexibleTopMargin = 1 << 3, //自动调整与superview顶部距离,底部距离保持不变 UIViewAutoresizingFlexibleHeight = 1 << 4, //自动调整控件自身高度,保证与superview上下距离不变 UIViewAutoresizingFlexibleBottomMargin = 1 << 5 //自动调整与superview底部距离,顶部距离保持不变 ;
通过注释大家应该大概了解每个枚举值的意义,但是我们知道枚举经常进行按位或操作(“|”),例如如果autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin那么iOS如何处理呢?此时会自动调整左边的距离和控件自身宽度,右侧距离不变,同时保证左侧距离和控件宽度同等比例的调整(延长或缩短)。例如在iPhone 5中,如果一个按钮假设自身宽度为200,左右侧距离均为60(左侧和宽度比例3:10),当从竖屏旋转到横屏的时候(此时宽度由320变为568,注意如果有状态栏则宽度变为568-20=548),由于右侧边距不变为60,根据比例左侧边距应该是(568-60)*(3/13)=117,宽度为:(568-60)*(10/13)=391。
请看下面的代码(下面例子通过纯代码方式创建iOS应用,并且自定义一个KCMainViewController):
AppDelegate.m
// // AppDelegate.m // UIViewAndUIScrollView // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "AppDelegate.h" #import "KCMainViewController.h" #import "KCTransformViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions self.window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].applicationFrame]; KCMainViewController *mainController=[[KCMainViewController alloc]init]; self.window.rootViewController=mainController; self.window.backgroundColor=[UIColor colorWithRed:249/255.0 green:249/255.0 blue:249/255.0 alpha:1]; [self.window makeKeyAndVisible]; return YES; - (void)applicationWillResignActive:(UIApplication *)application // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. - (void)applicationDidEnterBackground:(UIApplication *)application // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - (void)applicationWillEnterForeground:(UIApplication *)application // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. - (void)applicationDidBecomeActive:(UIApplication *)application // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - (void)applicationWillTerminate:(UIApplication *)application // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. @end
KCMainViewController.m
// // KCMainViewController.m // UIViewAndUIScrollView // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCMainViewController.h" @interface KCMainViewController () UIButton *_btn; //私有变量 @end @implementation KCMainViewController - (void)viewDidLoad [super viewDidLoad]; //添加一个Button _btn=[[UIButton alloc]initWithFrame:CGRectMake(60, 100, 200, 50)]; _btn.backgroundColor=[UIColor orangeColor]; [_btn setTitle:@"Hello,world!" forState:UIControlStateNormal]; _btn.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleLeftMargin; [self.view addSubview:_btn]; #pragma mark 屏幕旋转事件 -(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation NSLog(@"%@",NSStringFromCGRect(_btn.frame)); @end
在上面的代码中设置了window的背景为灰色,虽然上面有一个UIView但是我们可以看到最终效果是灰色的,这说明UIView默认是透明的。另外定义了一个私有成员变量_btn,这种定义方式大家以后会经常用到。
运行效果:
竖屏
横屏
注意上面执行前请先隐藏iOS状态栏目,全局隐藏iO状态栏的方法:
1.在info.plist 中设置Status bar is initially hidden为YES
2.在info.plist中设置View controller-based status bar appearance 为NO
transform
transform我们一般称为形变属性,其本质是通过矩阵变化改变控件的大小、位置、角度等,这里我们通过一个例子来看一下具体的操作,在下面的例子中我们也会看到UIImageView控件的常用操作。
KCTransformViewController.m
// // KCTransformViewController.m // UIViewAndUIScrollView // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCTransformViewController.h" //定义rgb颜色 #define NORMAL_COLOR [UIColor colorWithRed:75/255.0 green:160/255.0 blue:253/255.0 alpha:1] #define HIGHLIGHTED_COLOR [UIColor colorWithRed:197/255.0 green:221/225.0 blue:249/225.0 alpha:1] //按钮操作 typedef void(^ ButtonHandle)(); @interface KCTransformViewController () UIImageView *_imageView;//图片控件 UIButton *_btnRotation;//旋转按钮 UIButton *_btnScale;//缩放按钮 UIButton *_btnTranslate;//移动按钮 @end @implementation KCTransformViewController - (void)viewDidLoad [super viewDidLoad]; [self addImageView]; [self addRotationButton]; [self addScaleButton]; [self addTranslateButton]; #pragma mark 添加图片控件 -(void)addImageView //直接使用图片名称,系统会自动到资源文件中找到对应的文件 UIImage *image=[UIImage imageNamed:@"promo_ios8.png"]; //如果使用initWithImage进行初始化则控件大小会自动设置成图片大小 _imageView=[[UIImageView alloc]initWithImage:image]; _imageView.frame=CGRectMake(20, 20, 280, 154); //设置内容填充模式为等比例填充 _imageView.contentMode=UIViewContentModeScaleAspectFit; //self.view就是每个视图控制器中的view属性 [self.view addSubview:_imageView]; #pragma mark 添加旋转按钮 -(void)addRotationButton _btnRotation=[self getButton]; _btnRotation.frame=CGRectMake(20, 400, 280, 30); [_btnRotation setTitle:@"旋转" forState:UIControlStateNormal]; //添加按钮点击事件 [_btnRotation addTarget:self action:@selector(rotation:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_btnRotation]; #pragma mark 添加缩放按钮 -(void)addScaleButton //在上面一个按钮位置的基础上确认当前位置 CGRect scaleButtonFrame=_btnRotation.frame; scaleButtonFrame.origin.y+=40; _btnScale =[self getButton]; _btnScale.frame=scaleButtonFrame; [_btnScale setTitle:@"缩放" forState:UIControlStateNormal]; //添加按钮点击事件 [_btnScale addTarget:self action:@selector(scale:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_btnScale]; #pragma mark 添加移动按钮 -(void)addTranslateButton CGRect translateButtonFrame=_btnScale.frame; translateButtonFrame.origin.y+=40; _btnTranslate =[self getButton]; _btnTranslate.frame=translateButtonFrame; [_btnTranslate setTitle:@"移动" forState:UIControlStateNormal]; [_btnTranslate addTarget:self action:@selector(translate:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:_btnTranslate]; #pragma mark 图片旋转方法,注意参数中的btn表示当前点击按钮 -(void)rotation:(UIButton *)btn [self animation:^ //注意旋转角度必须是弧度,不是角度 CGFloat angle=M_PI_4;//M开头的宏都是和数学(Math)相关的宏定义,M_PI_4表示四分之派,M_2_PI表示2派 //使用CGAffineTransformMakeRotation获得一个旋转角度形变 //但是需要注意tranform的旋转不会自动在原来的角度上进行叠加,所以下面的方法旋转一次以后再点击按钮不会旋转了 //_imageView.transform=CGAffineTransformMakeRotation(angle); //利用CGAffineTransformRotate在原来的基础上产生一个新的角度(当然也可以定义一个全局变量自己累加) _imageView.transform=CGAffineTransformRotate(_imageView.transform, angle); ]; #pragma mark 图片缩放方法 -(void)scale:(UIButton *)btn // [self animation:^ // CGFloat scalleOffset=0.9; // //_imageView.transform=CGAffineTransformMakeScale(scalleOffset, scalleOffset); // _imageView.transform= CGAffineTransformScale(_imageView.transform, scalleOffset, scalleOffset); // ]; //通常我们使用UIView的静态方法实现动画而不是自己写一个方法 [UIView animateWithDuration:0.5 animations:^ CGFloat scalleOffset=0.9; //_imageView.transform=CGAffineTransformMakeScale(scalleOffset, scalleOffset); _imageView.transform= CGAffineTransformScale(_imageView.transform, scalleOffset, scalleOffset); ]; #pragma mark 图片移动方法 -(void)translate:(UIButton *)btn [self animation:^ CGFloat translateY=50; //_imageView.transform=CGAffineTransformMakeTranslation(0, translateY); _imageView.transform=CGAffineTransformTranslate(_imageView.transform, 0, translateY); ]; #pragma mark 动画执行方法,注意这里可以使用UIView的animateWithDuration方法代替这里只是为了演示 -(void)animation:(ButtonHandle)handle //开始动画 [UIView beginAnimations:@"animation" context:nil]; //设置动画执行时间 [UIView setAnimationDuration:0.5]; handle(); //执行动画操作 [UIView commitAnimations]; #pragma mark 取得一个按钮,统一按钮样式 -(UIButton *)getButton UIButton *button =[[UIButton alloc]init ]; //设置正常状态下字体颜色 [button setTitleColor:NORMAL_COLOR forState:UIControlStateNormal]; //设置高亮状态下的字体颜色 [button setTitleColor:HIGHLIGHTED_COLOR forState:UIControlStateHighlighted]; return button; @end
- 获得CGAffineTransform有多种方法,例如使用CGAffineTransformMake,但是对于矩阵操作相对比较麻烦,事实上iOS已经为我们准备好了三个方法:CGAffineTransformMakeRotation(旋转)、CGAffineTransformMakeScale(缩放)、CGAffineTransformMakeTranslation(移动);
- transform进行旋转、缩放、移动的时候不是在原来的基础上增量形变的,因此如果需要持续在原来的基础上旋转、缩放、移动那么每次需要在原来的基础上增加或减少。当然,我们可以定义一个全局变量进行累加,但是事实上iOS已经为我们提供好了三个对应的方法,分别用于在原来的角度、缩放、移动位置的基础上做出修改:CGAffineTransformRotate、CGAffineTransformScale、CGAffineTransformTranslate;
- Objc语法规定不允许直接修改一个对象的结构体属性的成员,只能给这个属性直接赋值为一个结构体类型,例如上面的代码中如果写成“_btnRotation.frame.origin.x=380;”是不正确的;
- 上面的代码中我们用到了UIView的动画相关方法,在iOS开发中动画开发异常简单,而且动画和逻辑处理是完全分离的,只要在两个动画方法之间修改一个控件的属性那么当代码执行时就会自动添加动画效果,为了复习前面的block这里我们实现了一个类似于animation方法,类似于UIView的animateWithDuration静态方法的功能,仅仅为了说明它的实现原理,实际开发中可以直接调用animateWithDuration即可(而且它有多种重载);
运行效果:
注意在iOS开发中推荐使用png图片,iOS会对png图片进行优化。
UIScrollView
通过上面的介绍相信大家对于UIView的基本操作应该比较熟悉了,那么下面就看一下UIView的子控件UIScrollView 。顾名思义,这是一个可以处理滚动操作的视图,UIScrollView在开发过程中使用很频繁,而且它也经常作为其他控件的子控件,例如UITableView就继承自UIScrollView。 我们还是先看一下UIScrollView的常用属性和方法:属性 | 说明 |
@property(nonatomic) CGPoint contentOffset; | 内容偏移量,当前显示的内容的顶点相对此控件顶点的x、y距离,默认为CGPointZero |
@property(nonatomic) CGSize contentSize; | 控件内容大小,不一定在显示区域,如果这个属性不设置,此控件无法滚动,默认为CGSizeZero |
@property(nonatomic) UIEdgeInsets contentInset; | 控件四周边距,类似于css中的margin,注意边距不作为其内容的一部分,默认为UIEdgeInsetsZero |
@property(nonatomic,assign) id<UIScrollViewDelegate> delegate; | 控件代理,一般用于事件监听,在iOS中多数控件都是通过代理进行事件监听的 |
@property(nonatomic) BOOL bounces; | 是否启用弹簧效果,启用弹簧效果后拖动到边缘可以看到内容后面的背景,默认为YES |
@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled; | 是否分页,如果分页的话每次左右拖动则移动宽度是屏幕宽度整数倍,默认为NO |
@property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled; | 是否启用滚动,默认为YES |
@property(nonatomic) BOOL showsHorizontalScrollIndicator; | 是否显示横向滚动条,默认为YES |
@property(nonatomic) BOOL showsVerticalScrollIndicator; | 是否显示纵向滚动条,默认为YES |
@property(nonatomic) CGFloat minimumZoomScale; | 最小缩放倍数,默认为1.0 |
@property(nonatomic) CGFloat maximumZoomScale; | 最大缩放倍数(注意只有maximumZoomScale大于minimumZoomScale才有可能缩放),默认为1.0 |
@property(nonatomic,readonly,getter=isTracking) BOOL tracking; | (状态)是否正在被追踪,手指按下去并且还没有拖动时是YES,其他情况均为NO |
@property(nonatomic,readonly,getter=isDragging) BOOL dragging; | 是否正在被拖拽 |
@property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating; | 是否正在减速 |
@property(nonatomic,readonly,getter=isZooming) BOOL zooming; | 是否正在缩放 |
方法 | 说明 |
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; | 设置滚动位置,第二个参数表示是否启用动画效果 |
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated; | 滚动并显示指定区域的内容,第二个参数表示是否启用动画效果 |
代理方法 | 说明 |
- (void)scrollViewDidScroll:(UIScrollView *)scrollView; | 滚动事件方法,滚动过程中会一直循环执行(滚动中…) |
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; | 开始拖拽事件方法 |
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; | 拖拽操作完成事件方法 |
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView; | 即将停止滚动事件方法(拖拽松开后开始减速时执行) |
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; | 滚动停止事件方法(滚动过程中减速停止后执行) |
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view NS_AVAILABLE_IOS(3_2); | 开始缩放事件方法 |
- (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2); | 缩放操作完成事件方法 |
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView; | 返回缩放视图,注意只有实现这个代理方法才能进行缩放,此方法返回需要缩放的视图 |
contentSize、contentInset、contentOffset在开发中会经常使用,为了帮助大家理解这里以图形的形式展现三者之间的关系:
关于上面列出的几个方法,我们有必要说一下它们的执行顺序:
a.如果我们拖动一个UIScrollView中的子控件移动的时候它的执行顺序如下:开始拖拽,滚动,滚动…,停止拖拽,将要停止滚动,滚动,滚动…,停止滚动。
红色部分有可能执行也有可能不执行,关键看你拖拽的停止的时候是突然停止还是有一段惯性让他继续执行(就好像刹车一样,如果是急刹车就没有后面的惯性滑动了,如果是慢慢踩刹车可能会有一段滑动距离)。但是不管怎么样滚动事件会一直执行,因此如果在这个事件中进行某种操作一定要注意性能。
b.如果我们缩放UIScrollView的子控件的时候它的执行顺序如下:开始缩放,滚动,滚动…,停止缩放。同样在这个过程中滚动事件会一直调用(当然如果缩放过程中手指有别的动作也可能会触发其他事件,这个大家可以自己体会一下)。
下面我们简单做一个例子
KCScrollViewController.h
// // KCScrollViewController.h // UIViewAndUIScrollView // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import <UIKit/UIKit.h> @interface KCScrollViewController : UIViewController @property (nonatomic,strong) UIScrollView *scrollView; @property (nonatomic,strong) UIImageView *imageView; @end
KCScrollViewController.m
// // KCScrollViewController.m // UIViewAndUIScrollView // // Created by Kenshin Cui on 14-2-23. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. // #import "KCScrollViewController.h" //实现UIScrollView代理 @interface KCScrollViewController ()<UIScrollViewDelegate> @end @implementation KCScrollViewController - (void)viewDidLoad [super viewDidLoad]; //添加scrollView控件 //注意UIScreen代表当前屏幕对象,其applicationFrame是当前屏幕内容区域 _scrollView =[[UIScrollView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame]; //_scrollView.backgroundColor=[UIColor redColor]; _scrollView.contentMode=UIViewContentModeScaleToFill; [self.view addSubview:_scrollView]; //添加图片控件 UIImage *image=[UIImage imageNamed:@"wwdc14-labs-hero-background.jpg"]; _imageView=[[UIImageView alloc]initWithImage:image]; [_scrollView addSubview:_imageView]; //contentSize必须设置,否则无法滚动,当前设置为图片大小 _scrollView.contentSize=_imageView.frame.size; //实现缩放:maxinumZoomScale必须大于minimumZoomScale同时实现viewForZoomingInScrollView方法 _scrollView.minimumZoomScale=0.6; _scrollView.maximumZoomScale=3.0; //设置代理 _scrollView.delegate=self; //边距,不属于内容部分,内容坐标(0,0)指的是内容的左上角不包括边界 //_scrollView.contentInset=UIEdgeInsetsMake(10, 20, 10, 20); //显示滚动内容的指定位置 //_scrollView.contentOffset=CGPointMake(10, 0); //隐藏滚动条 _scrollView.showsHorizontalScrollIndicator=NO; _scrollView.showsVerticalScrollIndicator=NO; //禁用弹簧效果 //_scrollView.bounces=NO; #pragma mark 实现缩放视图代理方法,不实现此方法无法缩放 -(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView return _imageView; -(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView NSLog(@"scrollViewWillBeginDecelerating"); -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView NSLog(@"scrollViewDidEndDecelerating"); -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView NSLog(@"scrollViewWillBeginDragging"); -(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate NSLog(@"scrollViewDidEndDragging"); -(void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view NSLog(@"scrollViewWillBeginZooming"); -(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale NSLog(@"scrollViewDidEndZooming"); //-(void)scrollViewDidScroll:(UIScrollView *)scrollView // NSLog(@"scrollViewDidScroll"); // #pragma mark 当图片小于屏幕宽高时缩放后让图片显示到屏幕中间 -(void)scrollViewDidZoom:(UIScrollView *)scrollView CGSize originalSize=_scrollView.bounds.size; CGSize contentSize=_scrollView.contentSize; CGFloat offsetX=originalSize.width>contentSize.width?(originalSize.width-contentSize.width)/2:0; CGFloat offsetY=originalSize.height>contentSize.height?(originalSize.height-contentSize.height)/2:0; _imageView.center=CGPointMake(contentSize.width/2+offsetX, contentSize.height/2+offsetY); @end
运行效果如下:
默认情况下缩放后的内容会放到UIScrollView的内容起始位置,所以如果要想缩放后内容放到中间我们必须自己维护它的位置,上面已经给出了设置方法。
扩展—ARC
iOS5之后引入了ARC特性,程序中不用自己retain、release、autorelease操作,编译器会自动为你管理内存,编译时自动加上内存释放的代码,使用起来很方便。ARC是编译器特性,而不是iOS运行时特性,其实质还是手动管理内存,只是相应内存管理的代码编译器会自动生成而已。由于ARC是编译器特性,因此它管理内存的规则和之前ObjC内存管理是类似的,只要有一个对象引用(强引用)指向这个对象,那么这个对象就不会被释放。
在开启ARC之后我们可以使用四个关键字修饰我们的成员变量、局部变量和属性:
- strong(修饰变量用__strong):强引用,相当于原来的retain,每次赋值引用计数器加1,只要指针引用这个对象,这个对象就不会被销毁;
- weak(修饰变量用__weak):弱引用,相当于assign,和assign不同的是当对象释放后该变量会设置为nil防止野指针(虽然之前讲过的内容中assign都是应用于基本数据类型,其实它也完全可以修饰对象类型的属性);
- unsafe_unretained(修饰变量用__unsafe_unretained):和weak类似,区别就是如果对象释放后它不会像weak一样自动将指针设置为nil,有可能出现野指针;
- __autoreleasing(只能修饰变量不能修饰属性):修饰一个对象在使用完之后自动释放,通常用于延迟释放内存,同在MRC下调用对象的autorelease方法是等效的;
注意:
- 除了weak(注意不是__weak)之外其他的修饰符在非ARC(MRC)下使用也不会报错,但是这么做并没有什么意义,因为在编译时会被忽略。举例来说:在MRC下使用__autoreleasing修饰一个对象也不会自动
以上是关于iOS开发系列--无限循环的图片浏览器的主要内容,如果未能解决你的问题,请参考以下文章