06 Subclassing UIView and UIScrollView

  • 972 views
Uploaded on

子类化 UIView 和 UIScrollView

子类化 UIView 和 UIScrollView

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
972
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
11
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. ⼦子类化 UIView 和 UIScrollView范圣刚,princetoad@gmail.com,www.tfan.org
  • 2. 什么是 view?• 我们在前⾯面创建过 UIButton,UILabel等,但是究 竟什么是 view? • ⼀一个 view 是 UIView 或者它的某⼀一⼦子类的实例 • view 知道如何把它⾃自⼰己绘制到应⽤用程序窗⼝口上(⼀一个 UIWindow 的实例) • view 存在于 view 的层次结构中 view hierarchy。view hierarchy 的根是应⽤用程序窗⼝口 • view 要处理事件,⽐比如触控事件
  • 3. ⾃自定义 UIView ⼦子类• 使⽤用同⼼心圆填满屏幕• 绘制⽂文本• 启⽤用滚动和放⼤大缩⼩小
  • 4. Hypnosister(催眠应⽤用)• 创建⼀一个新的 iOS 项⺫⽬目,空项⺫⽬目• 产品名:Hypnosister• 类前缀:Hypnosister• 勾选 “Use Automatic Reference Counting”
  • 5. 视图和视图层次结构
  • 6. • 视图构成了应⽤用的⽤用户界⾯面• 每个视图维护⼀一个⽤用于表⽰示它的图像,例如 UIButton 的图像就是⼀一个在中间带有标题的圆⾓角 矩形;⼀一个 UILabel 的图像就是简单的⽂文本• 当关于 view 的⼀一些东⻄西变化时,例如 UILabel 的 text 属性或 UIButton 的 title,view 的图像被重绘 以便这些变更能够在屏幕上变得可⻅见
  • 7. UIWindow • UIWindow 是 UIView 的⼦子类 • 每个应⽤用程序恰好有⼀一个 UIWindow 的实例作为 在应⽤用中所有视图的容器,当应⽤用启动的时候窗 ⼝口被创建 • HypnosisterAppDelegate.m 中的 application:didFinishLaunchingWithOptions: ⽅方 法中创建 UIWindow 对象并发送消息 makeKeyAndVisible- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 8. subview• window 被放到屏幕上以后,就可以在它上⾯面增加 其他 view,这样的 view 就叫做 window 的 subview• 作为 window 的 subview 的 view 也可以具有 subviews,结果就形成了⼀一个视图对象的层次结 构• 当且仅当⼀一个视图被添加到这个层次结构以后才 会在屏幕上显⽰示,⽆无论它是作为 window 的⼀一个 subview,还是作为另外⼀一个已经添加到 window 的 view 的 subview• 因此,window 是 view hierarchy 的 root
  • 9. redrawn(重绘)• 当屏幕被重绘的时候,⾸首先是 window 的图像被 绘制到屏幕上• 然后,window 的所有 subview 把它们⾃自⼰己的图像 绘制到屏幕上• 接着,subviews 的 subviews 再绘制它们的图像, 依此类推
  • 10. 绘制 view hierarchy 到屏幕
  • 11. ⽤用户界⾯面⽣生成• 创建每⼀一个 view 的图像并且把每⼀一个 view 加到 view hierarchy• 类似 UIButton,MKMapView 以及 UITextField 这些 (Apple本⾝身提供的)已经知道它们的图像看起来 是什么样⼦子• 另外⼀一种情况是我们需要创建⼀一个⾃自定义的视图 对象并且编写代码来创建它的图像
  • 12. 创建⼀一个⾃自定义视图
  • 13. • ⼦子类化 UIView,并且⾃自定义⼦子类的图像 • 创建⼀一个类 HypnosisView, 从 UIView 继承 • 在 HypnosisterAppDelegate.m 中引⼊入 HypnosisView.h 头⽂文件 • 在 application:didFinishLaunchingWithOptions: 中创建 HypnosisView 的实例并把它作为 window 的 subview 添加到 view hierarchy 中
  • 14. 创建 HypnosisView 的实例并添 加到UIWindow- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]bounds]]; CGRect viewFrame = CGRectMake(160, 240, 100, 150); HypnosisView *view = [[HypnosisView alloc] initWithFrame:viewFrame]; [view setBackgroundColor:[UIColor redColor]]; [[self window] addSubview:view]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 15. subview 和 superview• 红⾊色的 HypnosisView 实例 在⽩白⾊色的 UIWindow 之上绘 制;HypnosisView 实例是 UIWindow 的 subview• 把⼀一个 view 作为另外⼀一个 view 的 subview 添加时,反 向关系同时也⾃自动建⽴立了, HypnosisView 的 superview 是 UIWindow• XIB ⽂文件和编程创建
  • 16. initWithFrame:• 当编程创建⼀一个 view 时,我们使⽤用 alloc 和⼀一个 initializer message,就像我们创建任何其他对象 ⼀一样• UIView 的 designated initializer,同样也是 HypnosisView的,是:initWithFrame:• initWithFrame: 采⽤用 CGRect 结构作为参数,这个 CGRect 就是 view 的边框
  • 17. view 的 frame• 每个视图实例都有⼀一个 frame 矩形• 视图的 frame 指定了视图的⼤大⼩小和其相对于它的 superview 的位置• frame 由 CGRect 结构体表⽰示,并且包含成员 origin 和 size。这些成员也是结构体• orgin 是 CGPoint 类型,包含两个 float 成员:x 和 y• size 是 CGSize 类型,包含两个 float 成员: width 和 height• 结构体 structure 并不是 objective-c 对象,因此不 能给它们发送消息
  • 18. CGRect• view 总是⼀一个矩形
  • 19. 再画⼀一个 HypnosisView 作为 Window的 subview // 再创建⼀一个 HypnosisView CGRect anotherFrame = CGRectMake(20, 30, 50, 50); HypnosisView *anotherView = [[HypnosisView alloc] initWithFrame:anotherFrame]; [anotherView setBackgroundColor:[UIColor blueColor]]; [[self window] addSubview:anotherView];
  • 20. 两个 HypnosisViews 都作为 window 的 subview 的 view hierarchy
  • 21. 将⼀一个 HypnosisView 作为另⼀一个 HypnosisView 的 subview • ⼀一个 view 的 frame 是 相对于它的 superview 的,⽽而不是 window[[self window] addSubview:anotherView];[view addSubview:anotherView];
  • 22. ⼀一个 HypnosisView 作为另⼀一个HypnosisView 的 subview 的 view hierarchy
  • 23. drawRect: ⽅方法
  • 24. • 截⾄至⺫⽬目前,我们创建了⼀一个 UIView 的⼦子类,创建 了两个实例,把它们插⼊入到了 view hierarchy• 我们给这两个实例不同的 backgroundColor 以便 区分它们在屏幕上的位置和⼤大⼩小。组成 iOS 所有 界⾯面的 view,要能够绘制更多,⽽而不仅仅是带颜 ⾊色的矩形• 使视图变得有趣的绘制都发⽣生在 UIView 的 drawRect: ⽅方法中• 默认情况下,drawRect: 什么都不做。UIView ⼦子类 通过重写这个⽅方法来实现⾃自定义绘制。
  • 25. Core Graphic framework• 在我们重写 drawRect: 时,我们发出创建 UIView ⼦子类的实例图像的绘制指令,这些绘制指令都来 ⾃自 Core Graphics framework。• 这个框架在创建新项⺫⽬目时被⾃自动添加到 application target
  • 26. 绘制上下⽂文(drawing context)• 重写 drawRect: 的第⼀一步是获取 drawing context (绘制上下⽂文)的指针• 绘制上下⽂文维护绘制的状态(例如当前绘制的颜 ⾊色和画笔的厚度)和执⾏行绘制操作• 绘制操作会使⽤用当前的绘制状态进⾏行绘制• 在 drawRect: 结束时,上下⽂文⽣生成的图像就变成了 view 的图像
  • 27. CGContextRef• CGContextRef 被定义为 CGContext * - 指向 CGContext 的指针• Ref 后缀使得很容易区分指向 C 结构体的指针和指 向 Objective-C 对象的指针• 这⾥里的 ctx 指向了当前的绘制上下⽂文- (void)drawRect:(CGRect)rect{ CGContextRef ctx = UIGraphicsGetCurrentContext();}
  • 28. bounds• view 的图像和它出现在屏幕上是⼀一样⼤大⼩小,也就 是说和 view 的 frame ⼤大⼩小⼀一致• frame 描述了 view 相对于 view 的 superview 的⼤大 ⼩小• UIView 的名为 bounds 的 CGRect 属性给出了视图 和它的 superview ⽆无关的⼤大⼩小• 在 CGContextRef 上执⾏行的绘制操作必须落在 bounds 矩形区域内,否则会被剪切到这个矩形区 域
  • 29. 在 bounds 矩形中⼼心绘制⼀一个圆形- (void)drawRect:(CGRect)rect{ CGContextRef ctx = UIGraphicsGetCurrentContext(); CGRect bounds = [self bounds]; // 计算出 bounds 矩形的中⼼心 CGPoint center; center.x = bounds.origin.x + bounds.size.width / 2.0; center.y = bounds.origin.y + bounds.size.height / 2.0; // 圆的半径应该是和 view 的⼤大⼩小⼏几乎⼀一样的 float maxRadius = hypot(bounds.size.width, bounds.size.height) / 4.0; // 线条宽度应该是 10pt 宽 CGContextSetLineWidth(ctx, 10); // 线条的颜⾊色应该是灰⾊色(red/green/blue = 0.6, alpha = 1.0) CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0); // 增加⼀一个矩形到上下⽂文 - 这不会真正绘制矩形 CGContextAddArc(ctx, center.x, center.y, maxRadius, 0.0, M_PI * 2.0, YES); // 执⾏行绘制指令;使⽤用当前状态绘制当前形状 CGContextStrokePath(ctx);}
  • 30. 在 bounds 中⼼心绘制圆形
  • 31. backgroundColor• 在 HyposisterAppDelegate.m 中,移除设置 view 的背景颜⾊色的代码• 在 HypnosisView.m 中,重写 initWithFrame: 来设 置每个 HyposisView 的背景颜⾊色为 clear HypnosisView *view = [[HypnosisView alloc] initWithFrame:viewFrame]; [view setBackgroundColor:[UIColor redColor]]; [[self window] addSubview:view]; CGRect anotherFrame = CGRectMake(20, 30, 50, 50); HypnosisView *anotherView = [[HypnosisView alloc] initWithFrame:anotherFrame]; [anotherView setBackgroundColor:[UIColor blueColor]]; - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setBackgroundColor:[UIColor clearColor]]; } return self; }
  • 32. 默认填充颜⾊色 和 clearColor
  • 33. Core Graphics
  • 34. Core Graphics• 以 CG 开头的函数和类型都来⾃自于 Core Graphics framework, ⼀一套⽤用于 2D 绘图的 C 语⾔言 API• Core Graphics framework 的中⼼心是 CGContextRef: 所 有其他的 Core Graphics 函数和类型都以某种⽅方式和 绘制上下⽂文进⾏行交互,然后由上下⽂文来创建图像• 前⾯面⽤用到的 Core Graphics 函数: • 使⽤用 CGContextSetLineWidth 设置绘制状态 • 使⽤用 CGContextSetRGBStrokeColor 设置描边颜⾊色 • 使⽤用 CGContextAddArc 增加⼀一个 path 到上下⽂文(Arc 只是 path 的⼀一种)
  • 35. 绘制操作• 路径被添加到上下⽂文之后,我们就可以执⾏行⼀一个绘制操作了。三种绘制操作:• CGContextStrokePath • 沿着路径绘制线条(描边)• CGContextFillPaht • 填充由路径构成的形状• CGContextClip • 限制对由路径定义的区域的进⼀一步绘制操作
  • 36. 绘制⼀一系列的同⼼心圆 • ⼀一个绘制操作完成后,当前路径就被从上下⽂文中 移除 • 这样,要绘制多于⼀一个圆形的话,就需要为每个 圆形添加⼀一个路径到上下⽂文 // 圆的半径应该是和 view 的⼤大⼩小⼏几乎⼀一样的// float maxRadius = hypot(bounds.size.width, bounds.size.height) / 4.0; float maxRadius = hypot(bounds.size.width, bounds.size.height) / 2.0; // 线条宽度应该是 10pt 宽 CGContextSetLineWidth(ctx, 10); // 线条的颜⾊色应该是灰⾊色(red/green/blue = 0.6, alpha = 1.0) CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0); for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) { CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES); CGContextStrokePath(ctx); }
  • 37. 同⼼心圆绘制• 再改造⼀一下,去掉后来加的那个HypnosisView• 把剩下的HypnosisView 的⼤大⼩小改成跟屏幕⼀一般⼤大
  • 38. 修改 didFinishLaunchingWithOptions:- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]]; // 创建⼀一个 HypnosisView,⼤大⼩小和屏幕⼤大⼩小⼀一样⼤大 HypnosisView *view = [[HypnosisViewalloc] initWithFrame:[[self window]bounds]]; [[self window] addSubview:view]; // Override point for customizationafter application launch. self.window.backgroundColor = [UIColorwhiteColor]; [self.window makeKeyAndVisible]; return YES;}
  • 39. UIKit 绘制• 有⼀一些 Foundation 或者 UIKit 的类可以和 CGContextRef ⼀一起⼯工作
  • 40. UIColor • 例如:UIColor,⼀一个 UIColor 的实例表⽰示⼀一种颜 ⾊色,可以⽤用来设置上下⽂文当前⽤用来绘制的颜⾊色 • 可以把 CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0) 替换为 [[UIColor colorWithRed: 0.6 green:0.6 blue: 0.6 alpha:1] setStroke]; • UIColor 也预先准备了很多常⽤用的颜⾊色供使⽤用,可 以把上⾯面的代码改成:[[UIColor lightGrayColor] setStroke];CGContextSetRGBStrokeColor(ctx, 0.6, 0.6, 0.6, 1.0);[[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1] setStroke];
  • 41. NSString• NSString 能够绘制到 CGContextRef• 发送 drawInRect:withFont: 消息给⼀一个 NSString 将 会使⽤用给定的字体把这个字符串绘制到当前上下 ⽂文给定的矩形内• 在 HyposisView.m 中的 drawRect: 中代码的末尾增 加⼀一段代码 NSString *text = @"你快被催眠了."; UIFont *font = [UIFont boldSystemFontOfSize:28]; CGRect textRect; textRect.size = [text sizeWithFont:font]; textRect.origin.x = center.x - textRect.size.width / 2.0; textRect.origin.y = center.y - textRect.size.height / 2.0; [[UIColor blackColor] setFill]; [text drawInRect:textRect withFont:font];
  • 42. 绘制⽂文本
  • 43. 使⽤用阴影 // 设置当前上下⽂文填充⾊色为⿊黑⾊色 [[UIColor blackColor] setFill]; // 增加阴影。阴影将会向右移动4个points,向下移动3个points CGSize offset = CGSizeMake(4, 3); // 阴影颜⾊色使⽤用深灰⾊色 CGColorRef color = [[UIColor darkGrayColor] CGColor]; // 使⽤用这些参数设置上下⽂文的阴影,后续绘制都会使⽤用阴影 (blur,模糊,2.0) CGContextSetShadowWithColor(ctx, offset, 2.0, color); // 绘制字符串 [text drawInRect:textRect withFont:font];
  • 44. 带阴影的⽂文字
  • 45. UIImage• 有⼀一个类似的有⽤用的⽅方法 drawInRect: ⽤用于绘制⼀一 个 image 对象到⼀一个上下⽂文
  • 46. 重绘视图
  • 47. • 当⼀一个 UIView 实例收到 setNeedsDisplay 消息 时,会重绘它的图像• 当视图⼦子类可绘制内容变更时,会给⾃自⾝身发送 setNeedsDisplay 消息 • 例如⼀一个 UILabel 当它被发送 setText: 消息时会为重 新显⽰示⽽而标记⾃自⾝身(如果显⽰示的⽂文本变更的话必须要 重新绘制图像)• 重绘操作不会⽴立即执⾏行,⽽而是在 run loop 中进⾏行• 重绘和组合
  • 48. 使⽤用 Run Loop 重绘视图
  • 49. 增加 circleColor 属性• HypnosisView.h 中声明 circleColor 属性• HypnosisView.m 中 synthesize 这个属性• 更新 initWithFrame: ⽅方法创建⼀一个默认的 circleColor• 在 drawRect: 中设置上下⽂文描边颜⾊色使⽤用 circleColor ⽽而不是 light gray
  • 50. 增加 circleColor (代码)@interface HypnosisView : UIView@property (nonatomic, strong) UIColor *circleColor;@end@implementation HypnosisView@synthesize circleColor;- (id)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { [self setBackgroundColor:[UIColor clearColor]]; [self setCircleColor:[UIColor lightGrayColor]]; } return self;} CGContextSetLineWidth(ctx, 10); [[self circleColor] setStroke]; for (float currentRadius = maxRadius; currentRadius > 0; currentRadius -= 20) { CGContextAddArc(ctx, center.x, center.y, currentRadius, 0.0, M_PI * 2.0, YES); CGContextStrokePath(ctx); }
  • 51. 动作事件(Motion Events)
  • 52. • UIView 的超类 UIResponder 的实例,可以在设备 被晃动或者键盘上的按键被按下时成为 window 的 first responder 并将接收事件• 下⾯面我们把 HypnosisView 的实例作为 Hypnosister window 的 first responder ,晃动设备将发送消息 给 HypnosisView,并且这个⽅方法将改变它的 circleColor
  • 53. becomeFirstResponder• 在 HypnosisterAppDelegate.m 中告诉 HypnosisView 实例成为 first responder• becomeFirstResponder ⽅方法返回⼀一个布尔值,标明 接收对象是否成功的变成了 window 的 first responder BOOL success = [view becomeFirstResponder]; if (success) { NSLog(@"HypnosisView 成为 first responder"); } else { NSLog(@"⽆无法成为 first responder"); }
  • 54. canBecomeFirstResponder• ⼤大多数 UIResponder 对象收到 becomeFirstResponder 时返回 NO• 因为⼤大多数的视图,默认情况下只关⼼心和它们关联 的事件,并且它们(⼏几乎)总有机会处理这些事件• 举例来说,不管谁是 first responder ⼀一个被点击的 UIButton 总会被发送消息• 所以,⼀一个 responder 对象必须显式表明它希望变 成 first responder• 在 HypnosisView.m 中重写UIResponder 的 canBecomeFirstResponder 来返回 YES- (BOOL)canBecomeFirstResponder{ return YES; }
  • 55. 动作事件⽅方法(motion event methods) • 接收事件的⽅方法也是在 UIResponder 中实现的, 为了实例能够响应事件它们也必须在 UIResponder 的⼦子类中重写 • 为了处理 shakes,在 UIResponder ⼦子类中重写的 ⽅方法被称为 motion event methods(动作事件⽅方 法),其声明类似:- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
  • 56. motionBegan:withEvent: • 为了让 HypnosisView 能够知道⽤用户开始摇动设备 并且采取⾏行动,必须实现 motionBegan:withEvent: ⽅方法 • 在 HypnosisView.m 中重写这个⽅方法以便开始摇动 的时候改变 circleColor- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent*)event{ NSLog(@"设备开始摇动"); [self setCircleColor:[UIColor redColor]];}
  • 57. 发送 setNeedsDisplay 消息 • 当 HypnosisView 的 circleColor 改变时,实例变量 circleColor 被设置指向⼀一个新的 UIColor 实例 • 但是当这些发⽣生时,我们并没有告诉 HypnosisView 它需要重新绘制它的图像;我们必 须在 HypnosisView 改变了它的 circleColor 后给它 发送 setNeedsDisplay 消息 • 在 HypnosisView.m 中,实现 setCircleColor: 以在变 更 circleColor 实例变量后发送这个消息 • 此时再运⾏行应⽤用,摇动设备,圆形就变成了红⾊色- (void)setCircleColor:(UIColor *)clr{ circleColor = clr; [self setNeedsDisplay];}
  • 58. UIEventSubtype • UIEventSubtype 持有触发这个⽅方法的动作事件的 类型。根据类型定义,处理 shake 事件外还可能 会有其他事件也触发这个⽅方法 • 在 HypnosisView.m 中 增加⼀一⾏行⽤用于判断的代码: if (motion == UIEventSubtypeMotionShake)typedef NS_ENUM(NSInteger, UIEventSubtype) { UIEventSubtypeNone = 0, UIEventSubtypeMotionShake = 1, UIEventSubtypeRemoteControlPlay = 100, UIEventSubtypeRemoteControlPause = 101, UIEventSubtypeRemoteControlStop = 102, UIEventSubtypeRemoteControlTogglePlayPause = 103, UIEventSubtypeRemoteControlNextTrack = 104, UIEventSubtypeRemoteControlPreviousTrack = 105, UIEventSubtypeRemoteControlBeginSeekingBackward = 106, UIEventSubtypeRemoteControlEndSeekingBackward = 107, UIEventSubtypeRemoteControlBeginSeekingForward = 108, UIEventSubtypeRemoteControlEndSeekingForward = 109,};
  • 59. 使⽤用 UIScrollView
  • 60. • 当我们希望能够让⽤用户滚动显⽰示我们视图的时候,我们⼀一般会使我们的视图成为 UIScrollView 的subview
  • 61. UIScrollView 对象⽰示意图
  • 62. contentSize• 滚动视图⼀一般⽤用于⽐比屏幕⼤大的视图,滚动视图绘 制它的 subview 的⼀一个矩形部分,在滚动视图上 移动你的⼿手指或者平移时,改变的是 subview 的 矩形的位置• 可以把滚动视图看作是⼀一个观察⼝口(view port),滚动视图的⼤大⼩小就是这个观察⼝口的⼤大⼩小• 能够查看的区域⼤大⼩小是 UIScrollView 的 contentSize, ⼀一般就是UIScrollView 的 subview 的⼤大⼩小
  • 63. UIScrollView 及其内容区域
  • 64. 超⼤大号的 HypnosisView• 在 HypnosisterAppDelegate.m 中创建⼀一个超⼤大号 的 HypnosisView• 把⼤大号的 HypnosisView 放到⼀一个 scroll view 中• 把 scroll view 添加到 window
  • 65. 超⼤大号的 HypnosisView(代码) // 创建⼀一个和 window ⼀一样⼤大的 UIScrollView CGRect screenRect = [[self window] bounds]; UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:screenRect]; [[self window] addSubview:scrollView]; // 创建⼀一个是屏幕两倍⼤大的 HypnosisView,并添加到scroll view CGRect bigRect = screenRect; bigRect.size.width *= 2.0; bigRect.size.height *= 2.0; HypnosisView *view = [[HypnosisView alloc]initWithFrame:bigRect]; // 把 HypnosisView 作为 subview 添加到 scrollview,⽽而不是 window [scrollView addSubview:view]; // 告诉 scrollview 它的区域有多⼤大 [scrollView setContentSize:bigRect.size];
  • 66. 超⼤大号的 HypnosisView
  • 67. 平移和分⻚页(panning and paging)• 前⾯面我们⽤用 scroll view 来移动特别⼤大的 view• scroll view 也可以⽤用来在⼀一些不同的 view 实例之 间进⾏行平移• ⽐比如我们有两个屏幕⼤大⼩小的视图,⽤用户可以在它 们之间平移• 我们把前⾯面例⼦子中的 HypnosisView 再缩回跟原来 屏幕⼀一样⼤大⼩小,并且增加另外⼀一个同样⼤大⼩小的 HypnosisView 作为 UIScrollView 的 subview• 同样,把 contentSize 设成屏幕宽度的两倍,⾼高度 ⼀一样
  • 68. 平移(代码) // 创建⼀一个和 window ⼀一样⼤大的 UIScrollView CGRect screenRect = [[self window] bounds]; UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:screenRect]; [[self window] addSubview:scrollView]; CGRect bigRect = screenRect; bigRect.size.width *= 2.0; // 把⾼高度改成和屏幕⼀一样// bigRect.size.height *= 2.0;// HypnosisView *view = [[HypnosisView alloc] initWithFrame:bigRect]; HypnosisView *view = [[HypnosisView alloc] initWithFrame:screenRect]; // 把 HypnosisView 作为 subview 添加到 scrollview,⽽而不是 window [scrollView addSubview:view]; // 把另⼀一个 HypnosisView 的矩形移动右边屏幕外 screenRect.origin.x = screenRect.size.width; // 创建另外⼀一个 HypnosisView HypnosisView *anotherView = [[HypnosisView alloc] initWithFrame:screenRect]; [scrollView addSubview:anotherView]; // 同样告诉 scrollview 它的区域有多⼤大 [scrollView setContentSize:bigRect.size];
  • 69. 在两个 HypnosisView 间平移
  • 70. setPagingEnable: • 前⾯面移动视图的时候可以停在两个 HypnosisView 之间 • 要强制滚动视图的观察⼝口捕捉这些视图之⼀一,在 HypnosisterAppDelegate.m 中为 scroll view 打开 paging(分⻚页) • 这样再平移到两个视图中间时,就会⾃自动滚动到其中 ⼀一个视图 • paging 通过滚动视图的 contentSize / bounds 来分成 同样⼤大⼩小的 section 进⾏行显⽰示CGRect screenRect = [[self window] bounds];UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:screenRect];// 打开 paging[scrollView setPagingEnabled:YES];[[self window] addSubview:scrollView];
  • 71. 缩放(Zooming)• UIScrollView 还以可以放⼤大或者缩⼩小其内容• 要进⾏行缩放,scroll view 需要知道最⼩小和最⼤大缩放 级别,⽽而且需要知道要进⾏行缩放的视图• 把 HypnosisterAppDelegate.m 中的另⼀一个 HypnosisView 去掉,同时把 UIScrollView 的 contentSize 改回屏幕⼤大⼩小• 然后禁⽤用 paging,设置 zoom 属性,设置 UIScrollView 的 delegate
  • 72. Zooming(代码)CGRect screenRect = [[self window] bounds];UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:screenRect];// 设置缩放属性[scrollView setMinimumZoomScale:1.0];[scrollView setMaximumZoomScale:5.0];// 设置 scrollView 的 delegate[scrollView setDelegate:self];[[self window] addSubview:scrollView];CGRect bigRect = screenRect;HypnosisView *view = [[HypnosisView alloc] initWithFrame:screenRect];// 把 HypnosisView 作为 subview 添加到 scrollview,⽽而不是 window[scrollView addSubview:view];// 同样告诉 scrollview 它的区域有多⼤大(现在 scroll view 是屏幕⼤大⼩小)[scrollView setContentSize:bigRect.size];
  • 73. viewForZoomingInScrollView:• 构建并运⾏行,我们可以看到⼀一个 HypnosisView, 但是此时我们既不能平移也不能缩放• 要实现缩放,必须在 UIScrollView 的 delegate 中 实现 viewForZoomingInScrollView: ⽅方法• 这个⽅方法返回在其上进⾏行缩放的 view 的实例,这 ⾥里的这个 view 应该是 HypnosisView 的实例, UIScrollView 的 delegate 将是 HypnosisterAppDelegate
  • 74. 实现 viewForZoomingInScrollView• 在 HypnosisterAppDelegate.h 中,声明 HypnosisterAppDelegate 遵守 UIScrollViewDelegate• 在 HypnosisterAppDelegate 中把指向 HypnosisView 的本地变量改成实例变量,以便在 viewForZoomingInScrollView: 中可以访问• 实现 viewForZoomingInScroolView 来返回这个 view
  • 75. 实现 viewForZoomingInScrollView(代码)#import <UIKit/UIKit.h>// 导⼊入 HypnosisView 头⽂文件#import "HypnosisView.h"@interface HypnosisterAppDelegate : UIResponder <UIApplicationDelegate,UIScrollViewDelegate>{ HypnosisView *view;}@property (strong, nonatomic) UIWindow *window;@end// HypnosisView *view = [[HypnosisView alloc] initWithFrame:screenRect]; view = [[HypnosisView alloc] initWithFrame:screenRect]; [scrollView addSubview:view];- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{ return view;}
  • 76. Zooming HypnosisView• 在模拟器上可以通过 按住 Option 键来模拟 两个⼿手指,然后点击 并移动⿏鼠标
  • 77. 隐藏状态栏 • 在窗⼝口可⻅见前隐藏状态栏 • 在 HypnosisterAppDelegate.m 中的 application:didFinishLaunchingWithOptions: 接近 顶部的地⽅方添加⼀一⾏行代码 • 再构建并运⾏行时,会发现状态栏在应⽤用程序启动 以后会逐渐消失(fading out) // 隐藏状态栏 status bar [[UIApplication sharedApplication]setStatusBarHidden:YESwithAnimation:UIStatusBarAnimationFade];
  • 78. 设置属性在显⽰示前隐藏状态栏• 也可以通过往应⽤用程序的信息属性列表(info property list)中添加⼀一个新的键值对在应⽤用程序 出现在屏幕前隐藏状态栏• 选择 Hypnosister target,然后选择 Info ⾯面板,在 最后⼀一⾏行点 “+” 图标,会显⽰示⼀一个新⾏行• 在新⾏行的 Key 列中,选择 “Status bar is initially hidden”, 在 Value 列中把值从NO改成 YES
  • 79. 隐藏状态栏的 Info property list
  • 80. 隐藏了状态栏的窗⼝口