08 Notification and Rotation

31
通知和翻转 范圣刚,[email protected] , www.tfan.org

description

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

Transcript of 08 Notification and Rotation

Page 2: 08 Notification and Rotation

•Objective-C 代码都是有关 objects 发送 messages 给其他的 objects。这个通讯⼀一般是发⽣生在两个 object 之间,但是有时候⼀一堆 objects 都关⼼心⼀一个 object

•他们都想知道这个对象什么时候在做⼀一些它们感兴趣的事,⽽而由这个 object 来给每⼀一个感兴趣的 object 来发送消息⼜又不可⾏行

Page 3: 08 Notification and Rotation

•相反,⼀一个对象可以发布关于它们正在做什么的通知给⼀一个中央通知中⼼心。感兴趣的对象进⾏行注册以在特定通知被发布的时候接收⼀一个消息,或者当⼀一个特定的对象进⾏行了发布

•这个章节我们将会学习如何使⽤用 noti!cation center 来处理 noti!cation,同时我们也会学习有关 UIViewController 的⾃自动翻转特性

Page 4: 08 Notification and Rotation

通知中⼼心 (Noti!cation Center)

Page 5: 08 Notification and Rotation

•每个应⽤用程序都有⼀一个 NSNoti!cationCenter 的实例,它就像⼀一个智能布告栏

•⼀一个对象可以作为⼀一个观察者注册(“”Send me ‘lost dog’ noti!cation)

•当另⼀一个对象发布了⼀一个通知(“I lost my dog”), noti!cation center 就会转发这个通知给已注册观察者

Page 6: 08 Notification and Rotation

NSNoti!cation

Page 7: 08 Notification and Rotation

NSNoti!cation

•这些 Noti!cations 都是 NSNoti!cation 的实例

•每个 NSNoti!cation 对象都有⼀一个 name,以及⼀一个回指到发布它的对象的指针 object

•当你注册为⼀一个观察者时,你可以指定⼀一个 noti!cation name,⼀一个 posting object,以及当⼀一个符合条件的通知发布时发送给你的 message

Page 8: 08 Notification and Rotation

name 和 object

•下⾯面的代码⽚片段为名为 LostDog ,发布者可以是任意对象的通知⽽而注册

•当⼀一个对象发布了⼀一个 LostDog 通知,将会有⼀一个 retrieveDog: 消息发给你

•注意 nil 在这⾥里的作⽤用是通配符,也可以把 nil 作为 name 的参数,这样会不管它的名称⽽而把所有的通知都给你

•把 noti!cation name 和 posting object 都设成 nil ,你将会收到所有的通知

NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self // 将会发给对象 self selector:@selector(retrieveDog:) // retrieveDog: name:@"LostDog" // 当 @"LostDog" 被发布,发布者可以是 object:nil]; // 任意对象

Page 9: 08 Notification and Rotation

作为参数的 NSNoti!cation

•当通知到达时被触发的⽅方法采⽤用⼀一个 NSNoti!cation 对象作为参数

- (void)retrieveDog:(NSNotification *)note{ id poster = [note object]; NSString *name = [note name]; NSDictionary *extraInformation = [note userInfo];}

Page 10: 08 Notification and Rotation

userInfo

• noti!cation 对象也可以具有⼀一个附加到它上⾯面的 userInfo dictionary,这个 dictionary 被⽤用来传递附加信息,例如对找到的狗的⼀一些描述

•另外⼀一个实际开发中的例⼦子,当 keyboard 出现在屏幕上的时候,它发布⼀一个包含 userInfo 的 UIKeyboardDidShowNoti!cation 。这个 userInfo dictionary 包含的是新的可⻅见键盘所占的屏幕区域

NSDictionary *extraInfo = [NSDictionary dictionaryWithObject:@"Fido" forKey:@"Name"];NSNotification *note = [NSNotification notificationWithName:@"LostDog" object:self userInfo:extraInfo];[[NSNotificationCenter defaultCenter] postNotification:note];

Page 11: 08 Notification and Rotation

观察者的强引⽤用• noti!cation center 保存对它的观察者们的强引⽤用

•如果对象在它被销毁前没有把它⾃自⾝身作为观察者移除,那么下次在它注册的⼀一个通知发布的时候,中⼼心会尝试发给对象⼀一个消息。因为对象已经不存在了,应⽤用程序将会 crash

•所以,如果⼀一个对象在通知中⼼心注册了,那么这个对象必须在它的 dealloc ⽅方法中取消注册(unregister)

- (void)dealloc{ [[NSNotificationCenter defaultCenter] removeObserver:self];}

Page 12: 08 Notification and Rotation

UIDevice 通知

Page 13: 08 Notification and Rotation

•⼀一个经常发布通知的对象是 UIDevice

•这⾥里是作为 UIDevice 发布的通知的名称的常量:

• UIDeviceOrientationDidChangNoti!cation

• UIDeviceBatteryStateDidChangeNoti!cation

• UIDeviceBatteryLevelDidChangeNoti!cation

• UIDeviceProximityStateDidChangeNoti!cation

•从上⾯面这些通知名称我们可以看到,我们可以在⼿手机屏幕翻转,距离我们⾯面部很近时,以及电量(等跟设备相关的信息)发⽣生变化的情况下得到通知

Page 14: 08 Notification and Rotation

HeavyRotation 项⺫⽬目•新建⼀一个 Empty Application 项⺫⽬目,命名为

HeavyRotation

•输⼊入 Rotation 作为 Class Pre!x

• iPhone 作为 Device Family

•仅勾选“Use Automatic Reference Counting”

Page 15: 08 Notification and Rotation

注册 UIDeviceOrientationDidChangeNoti!cation

- (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;}

Page 16: 08 Notification and Rotation

实现通知消息(⽅方法)•这样当设备的 orientation 变更时,

orientationChanged: 消息就会被发送给 RotationAppDelegate 的实例

•在同⼀一个⽂文件中添加 orientationChanged: ⽅方法

- (void)orientationChanged:(NSNotification *)note{ NSLog(@"orientationChanged: %d", [[note object] orientation]);}

Page 17: 08 Notification and Rotation

UIDeviceOrientation

typedef 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, face down};

Page 18: 08 Notification and Rotation

能够发布通知的⼀一些类•注意消息后⾯面的冒号是⽅方法名称的⼀一部分 -

orientationChanged:

•可以发布通知的⼀一些类:• UIApplication

• NSManagedObjectContext

• MPMoviePlayerController

• NSFileHandle

• UIWindow

• UITextField

• UITextView

Page 19: 08 Notification and Rotation

⾃自动翻转 - Autorotation

Page 20: 08 Notification and Rotation

•很多应⽤用程序在⽤用户旋转设备的时候会把所有的视图旋转并调整⼤大⼩小

•我们可以使⽤用 UIDevice noti!cation 来实现这个,但这会是⼀一个很⼤大量的⼯工作。幸运的是,我们可以使⽤用 autorotation 来简化这个过程

Page 21: 08 Notification and Rotation

•如果屏幕上的视图通过⼀一个 view controller 被控制,当设备被翻转时,这个 view controller 会被询问是否可以翻转 view 。如果 view controller 同意的话,view 被调整⼤大⼩小并且翻转。所有的 subviews 也被调整⼤大⼩小和翻转

Page 22: 08 Notification and Rotation

HeavyViewController

•我们实现⼀一个 UIViewController 的⼦子类来获得⾃自动翻转特性。这个 view controller 的 view 会拥有 subviews,所以我们使⽤用带 XIB ⽂文件的 UIViewController 模版来创建这个类

•选择 File -> New -> File..., 从 iOS 部分,选择 Cocoa Touch, 选择 Objective-C 类模版

•命名⼦子类为 HeavyViewController, 选择 UIViewController 作为超类,勾选 “With XIB for user interface”

Page 23: 08 Notification and Rotation

实现 autorotation

•这样我们就有了⼀一个名为 HeavyViewController 的 UIViewController ⼦子类

•同时也有了⼀一个名为 HeavyViewController.xib 的 XIB ⽂文件

•这个 XIB ⽂文件有⼀一个类型是 HeavyViewController 的 File’s Owner, 它的 view outlet 被连接到了⼀一个 320x460(548)点⼤大⼩小的 view 对象

Page 24: 08 Notification and Rotation

•要在 HeavyRotation 中实现 autorotation,我们需要做下⾯面两个⼯工作:

•在 HeavyViewController 中重写 shouldAutorotateToInterfaceOrientation: 以允许 autorotation

•针对每个 subview ⼩小⼼心的设置 autoresize mask 以在 superview 被调整到填充被翻转的窗⼝口时表现合理

Page 25: 08 Notification and Rotation

设备翻转:iPhone 和 iPad

•当设备翻转时,当前显⽰示在屏幕上的 view 的 view controller 将被发送⼀一个 shouldAutorotationToInterfaceOrientation: 消息。这个⽅方法返回⼀一个 BOOL 来标明是否可以翻转这个 view controller 的 view

Page 26: 08 Notification and Rotation

设备翻转: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);}

Page 27: 08 Notification and Rotation

HeavyViewController XIB 布局•增加⼀一些内容来翻转•拖⼀一张图⽚片到 project

navigator 中

•打开 HeavyViewController.xib, 在 view 上放⼀一个 slider,⼀一个 image view,两个 button

Page 28: 08 Notification and Rotation

UIImageView 属性•设置 UIImageView 的属性为刚才的图⽚片⽂文件,设置 Mode 为 Aspect Fit,设置背景颜⾊色为 Light Gray

Page 29: 08 Notification and Rotation

autoresizing mask

•当设备翻转时,⾸首先 view 被翻转到和设备的朝向对⻬齐;其次 view 的⼤大⼩小被调整到适合屏幕

•在 portrait 模式下的 320 宽和 480 ⾼高的 view 将变成 480 宽和 320 ⾼高的 landscape 模式

•当 view 被调整⼤大⼩小时,它将 autoresize 它的所有 subview

•每个 subview 被根据它的 autosizing mask 属性进⾏行调整

•可以通过在 XIB ⽂文件中选择⼀一个 view,然后在 size inspector 中编辑 autoresizing mask

Page 30: 08 Notification and Rotation

Autoresizing 设置• image view 应该保持在中间位置

•滑块应该变宽,和 superview 的顶部保持固定距离,并且和左右边界保持同样距离

•两个按钮应该停留在它们相应的 corner 并且不⾃自动调整⼤大⼩小

Page 31: 08 Notification and Rotation

设成 rootViewController

•创建⼀一个 HeavyViewController 的实例,并且把它设置成 window 的 rootViewController

- (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]; [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;}