08 Notification and Rotation

608 views

Published on

iOS 通知和翻转,观察者模式, 通知中心, UIDevice 通知

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
608
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

08 Notification and Rotation

  1. 1. 通知和翻转范圣刚,princetoad@gmail.com, www.tfan.org
  2. 2. • Objective-C 代码都是有关 objects 发送 messages 给其他的 objects。这个通讯⼀一般是发⽣生在两个 object 之间,但是有时候⼀一堆 objects 都关⼼心⼀一个 object• 他们都想知道这个对象什么时候在做⼀一些它们感 兴趣的事,⽽而由这个 object 来给每⼀一个感兴趣的 object 来发送消息⼜又不可⾏行
  3. 3. • 相反,⼀一个对象可以发布关于它们正在做什么的 通知给⼀一个中央通知中⼼心。感兴趣的对象进⾏行注 册以在特定通知被发布的时候接收⼀一个消息,或 者当⼀一个特定的对象进⾏行了发布• 这个章节我们将会学习如何使⽤用 notification center 来处理 notification,同时我们也会学习有 关 UIViewController 的⾃自动翻转特性
  4. 4. 通知中⼼心 (Notification Center)
  5. 5. • 每个应⽤用程序都有⼀一个 NSNotificationCenter 的实 例,它就像⼀一个智能布告栏• ⼀一个对象可以作为⼀一个观察者注册(“”Send me ‘lost dog’ notification)• 当另⼀一个对象发布了⼀一个通知(“I lost my dog”), notification center 就会转发这个通知给已注册观 察者
  6. 6. NSNotification
  7. 7. NSNotification• 这些 Notifications 都是 NSNotification 的实例• 每个 NSNotification 对象都有⼀一个 name,以及⼀一 个回指到发布它的对象的指针 object• 当你注册为⼀一个观察者时,你可以指定⼀一个 notification name,⼀一个 posting object,以及当⼀一 个符合条件的通知发布时发送给你的 message
  8. 8. name 和 object• 下⾯面的代码⽚片段为名为 LostDog ,发布者可以是任意 对象的通知⽽而注册• 当⼀一个对象发布了⼀一个 LostDog 通知,将会有⼀一个 retrieveDog: 消息发给你• 注意 nil 在这⾥里的作⽤用是通配符,也可以把 nil 作为 name 的参数,这样会不管它的名称⽽而把所有的通知 都给你• 把 notification name 和 posting object 都设成 nil ,你 将会收到所有的通知 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self // 将会发给对象 self selector:@selector(retrieveDog:) // retrieveDog: name:@"LostDog" // 当 @"LostDog" 被发布,发布者可以是 object:nil]; // 任意对象
  9. 9. 作为参数的 NSNotification• 当通知到达时被触发的⽅方法采⽤用⼀一个 NSNotification 对象作为参数- (void)retrieveDog:(NSNotification *)note{ id poster = [note object]; NSString *name = [note name]; NSDictionary *extraInformation = [note userInfo];}
  10. 10. userInfo • notification 对象也可以具有⼀一个附加到它上⾯面的 userInfo dictionary,这个 dictionary 被⽤用来传递附 加信息,例如对找到的狗的⼀一些描述 • 另外⼀一个实际开发中的例⼦子,当 keyboard 出现在 屏幕上的时候,它发布⼀一个包含 userInfo 的 UIKeyboardDidShowNotification 。这个 userInfo dictionary 包含的是新的可⻅见键盘所占的屏幕区域NSDictionary *extraInfo = [NSDictionary dictionaryWithObject:@"Fido"forKey:@"Name"];NSNotification *note = [NSNotification notificationWithName:@"LostDog" object:self userInfo:extraInfo];[[NSNotificationCenter defaultCenter] postNotification:note];
  11. 11. 观察者的强引⽤用• notification center 保存对它的观察者们的强引⽤用• 如果对象在它被销毁前没有把它⾃自⾝身作为观察者 移除,那么下次在它注册的⼀一个通知发布的时 候,中⼼心会尝试发给对象⼀一个消息。因为对象已 经不存在了,应⽤用程序将会 crash• 所以,如果⼀一个对象在通知中⼼心注册了,那么这 个对象必须在它的 dealloc ⽅方法中取消注册 (unregister)- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self];}
  12. 12. UIDevice 通知
  13. 13. • ⼀一个经常发布通知的对象是 UIDevice• 这⾥里是作为 UIDevice 发布的通知的名称的常量:• UIDeviceOrientationDidChangNotification• UIDeviceBatteryStateDidChangeNotification• UIDeviceBatteryLevelDidChangeNotification• UIDeviceProximityStateDidChangeNotification• 从上⾯面这些通知名称我们可以看到,我们可以在⼿手机屏幕翻转,距离我们⾯面部很近时,以及电量(等跟设备相关的信息)发⽣生变化的情况下得到通知
  14. 14. HeavyRotation 项⺫⽬目• 新建⼀一个 Empty Application 项⺫⽬目,命名为 HeavyRotation• 输⼊入 Rotation 作为 Class Prefix• iPhone 作为 Device Family• 仅勾选“Use Automatic Reference Counting”
  15. 15. 注册 UIDeviceOrientationDidChangeNotification- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. // 得到设备对象 UIDevice *device = [UIDevice currentDevice]; // 请设备开始监视 orientation 的 accelerometer [device beginGeneratingDeviceOrientationNotifications]; // 得到 app 的 notification center NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; // 把⾃自⼰己添加为观察者 [nc addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:device]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}
  16. 16. 实现通知消息(⽅方法)• 这样当设备的 orientation 变更时, orientationChanged: 消息就会被发送给 RotationAppDelegate 的实例• 在同⼀一个⽂文件中添加 orientationChanged: ⽅方法 - (void)orientationChanged:(NSNotification *)note { NSLog(@"orientationChanged: %d", [[note object] orientation]); }
  17. 17. UIDeviceOrientationtypedef NS_ENUM(NSInteger, UIDeviceOrientation) { UIDeviceOrientationUnknown, UIDeviceOrientationPortrait, // Device oriented vertically,home button on the bottom UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically,home button on the top UIDeviceOrientationLandscapeLeft, // Device oriented horizontally,home button on the right UIDeviceOrientationLandscapeRight, // Device oriented horizontally,home button on the left UIDeviceOrientationFaceUp, // Device oriented flat, face up UIDeviceOrientationFaceDown // Device oriented flat, facedown};
  18. 18. 能够发布通知的⼀一些类• 注意消息后⾯面的冒号是⽅方法名称的⼀一部分 -orientationChanged:• 可以发布通知的⼀一些类:• UIApplication• NSManagedObjectContext• MPMoviePlayerController• NSFileHandle• UIWindow• UITextField• UITextView
  19. 19. ⾃自动翻转 - Autorotation
  20. 20. • 很多应⽤用程序在⽤用户旋转设备的时候会把所有的 视图旋转并调整⼤大⼩小• 我们可以使⽤用 UIDevice notification 来实现这个, 但这会是⼀一个很⼤大量的⼯工作。幸运的是,我们可 以使⽤用 autorotation 来简化这个过程
  21. 21. • 如果屏幕上的视图通过⼀一个 view controller 被控 制,当设备被翻转时,这个 view controller 会被询 问是否可以翻转 view 。如果 view controller 同意 的话,view 被调整⼤大⼩小并且翻转。所有的 subviews 也被调整⼤大⼩小和翻转
  22. 22. HeavyViewController• 我们实现⼀一个 UIViewController 的⼦子类来获得⾃自动 翻转特性。这个 view controller 的 view 会拥有 subviews,所以我们使⽤用带 XIB ⽂文件的 UIViewController 模版来创建这个类• 选择 File -> New -> File..., 从 iOS 部分,选择 Cocoa Touch, 选择 Objective-C 类模版• 命名⼦子类为 HeavyViewController, 选择 UIViewController 作为超类,勾选 “With XIB for user interface”
  23. 23. 实现 autorotation• 这样我们就有了⼀一个名为 HeavyViewController 的 UIViewController ⼦子类• 同时也有了⼀一个名为 HeavyViewController.xib 的 XIB ⽂文件• 这个 XIB ⽂文件有⼀一个类型是 HeavyViewController 的 File’s Owner, 它的 view outlet 被连接到了⼀一个 320x460(548)点⼤大⼩小的 view 对象
  24. 24. • 要在 HeavyRotation 中实现 autorotation,我们需 要做下⾯面两个⼯工作: • 在 HeavyViewController 中重写 shouldAutorotateToInterfaceOrientation: 以允许 autorotation • 针对每个 subview ⼩小⼼心的设置 autoresize mask 以在 superview 被调整到填充被翻转的窗⼝口时表现合理
  25. 25. 设备翻转:iPhone 和 iPad• 当设备翻转时,当前显⽰示在屏幕上的 view 的 view controller 将被发送⼀一个 shouldAutorotationToInterfaceOrientation: 消息。这 个⽅方法返回⼀一个 BOOL 来标明是否可以翻转这个 view controller 的 view
  26. 26. 设备翻转:iPhone 和 iPad • 对于 iPhone 应⽤用⽽而⾔言,我们⼀一般允许 right-side up(正⽴立), landscape left(平放左边在上), 和 landscape right(平放右边在上);在 iPad 上,⼀一 般允许全部⽅方向,包括 upside-down(倒⽴立) • 我们在 HeavyViewController.m 中,为两种常⻅见的 iPhone 朝向返回 YES- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationPortrait) || UIInterfaceOrientationIsLandscape(toInterfaceOrientation);}
  27. 27. HeavyViewController XIB 布局• 增加⼀一些内容来翻转• 拖⼀一张图⽚片到 project navigator 中• 打开 HeavyViewController.xi b, 在 view 上放⼀一个 slider,⼀一个 image view,两个 button
  28. 28. UIImageView 属性• 设置 UIImageView 的 属性为刚才的图⽚片⽂文 件,设置 Mode 为 Aspect Fit,设置背景颜 ⾊色为 Light Gray
  29. 29. autoresizing mask• 当设备翻转时,⾸首先 view 被翻转到和设备的朝向 对⻬齐;其次 view 的⼤大⼩小被调整到适合屏幕• 在 portrait 模式下的 320 宽和 480 ⾼高的 view 将变 成 480 宽和 320 ⾼高的 landscape 模式• 当 view 被调整⼤大⼩小时,它将 autoresize 它的所有 subview• 每个 subview 被根据它的 autosizing mask 属性进 ⾏行调整• 可以通过在 XIB ⽂文件中选择⼀一个 view,然后在 size inspector 中编辑 autoresizing mask
  30. 30. Autoresizing 设置• image view 应该保持在中间位置• 滑块应该变宽,和 superview 的顶部保持固定距 离,并且和左右边界保持同样距离• 两个按钮应该停留在它们相应的 corner 并且不⾃自 动调整⼤大⼩小
  31. 31. 设成 rootViewController • 创建⼀一个 HeavyViewController 的实例,并且把它 设置成 window 的 rootViewController- (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]bounds]]; // Override point for customization after application launch. UIDevice *device = [UIDevice currentDevice]; [device beginGeneratingDeviceOrientationNotifications]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:device]; HeavyViewController *hvc = [[HeavyViewController alloc] init]; [[self window] setRootViewController:hvc]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES;}

×