UIwindow 的学习
层级关系测试代码:
@interface AppDelegate () @property (nonatomic, strong) UIWindow *arlewWindow; @property (nonatomic, strong) UIWindow *norWindow; @property (nonatomic, strong) UIWindow *statusWindow; @end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // UIStoryboard中没有设置了程序入口箭头 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.backgroundColor = [UIColor greenColor]; UIStoryboard *story = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UIViewController *oneView = [story instantiateViewControllerWithIdentifier:@"123"]; self.window.rootViewController = oneView; NSLog(@"%f",self.window.windowLevel); [self.window makeKeyAndVisible]; // 最低级别 UIWindow *norWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 520)]; self.norWindow = norWindow; norWindow.windowLevel = UIWindowLevelNormal + 1; norWindow.backgroundColor = [UIColor redColor]; NSLog(@"norWindow.windowLevel:%f",norWindow.windowLevel); [norWindow makeKeyAndVisible]; // 中等级别 UIWindow *statusWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 50, 100, 100)]; self.statusWindow = statusWindow; statusWindow.windowLevel = UIWindowLevelStatusBar; statusWindow.backgroundColor = [UIColor grayColor]; NSLog(@"statusWindow.windowLevel:%f",statusWindow.windowLevel); [statusWindow makeKeyAndVisible]; // 最高级别 UIWindow *arlewWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 100, 320, 30)]; self.arlewWindow = arlewWindow; arlewWindow.windowLevel = UIWindowLevelAlert; arlewWindow.backgroundColor = [UIColor yellowColor]; NSLog(@"arlewWindow.windowLevel:%f",arlewWindow.windowLevel); [arlewWindow makeKeyAndVisible]; // 经过总结,self.window.windowLevel默认是UIWindowLevelNormal,window按照层级级别来显示,不管谁先谁后makeKeyAndVisible,层级最高的总是显示在前面,如果是相同层级的window,按照显示顺序是按照 [_window makeKeyAndVisible];的顺序显示,最后makeKeyAndVisible的window显示在最前面。小技巧:如果想要设置不大不小的层级级别,可以norWindow.windowLevel = UIWindowLevelNormal + 1;来增加级别权限。 // 如果是非ARC模式测验则没问题,但是在ARC模式下测验则会不显示其他window,只会显示self.window,因为其他的window没有strong进行引用,没有人持有,会被释放掉,如果想在ARC下测试,则要将window定义为类的属性 return YES; }
// 通过遍历以及打印信息提取自己想要的app中得window for (UIWindow *window in [UIApplication sharedApplication].windows) { NSLog(@"window:%@, %f",window, window.windowLevel); } // 取出self.window UIWindow *window = [[UIApplication sharedApplication].windows objectAtIndex:2]; // 增加self.window的层级权限 window.windowLevel = UIWindowLevelNormal + 30;
如果你的window在某个类中做为属性创建,并且使用完后保证没有其他地方strong引用window的话,那么这个类释放的时候,window属性自然就释放了。
[UIApplication sharedApplication].windows // 在本应用中打开的UIWindow列表
[UIApplication sharedApplication].keyWindow //(获取应用程序的主窗口)
//UIScreen屏幕属性
@property(nonatomic,retain) UIScreen *screen
keyWindow
官方解释keyWindow是唯一一个可以接受响应的Window,在一个应用程序中只有唯一一个keyWindow
但是iOS7.0检验发现非keyWindow也是可以接受键盘消息,这一点和文档上说的不太一样。
层级
// UIWindowLevel属性(层级高度)
@property(nonatomic) UIWindowLevel windowLevel;
// 定义UIWindow展示优先级不同层次的选择 ,根据window显示级别优先的原则,级别高的灰显示在上面,级别低的在下面,我们程序正常显示的位于最底层
UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal; //默认的window就是Normal级别,优先级值这个层次的值为0,通常我们程序的界面都是处于这个Normal级别的
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert; //屏幕的statusBar处于中等水平,优先级值为1000
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar;// alert级别的,通常是UIAlertView和UIAlertSheet这些用来中断正常流程,提醒用户等操作的。优先级值为2000.按照这样说来,alertView弹框出来下面也是一层UIWindow,只不过是优先级最高的alert级别,所以是keyWindow,当前只能交互alert,这就是为什么弹框出来其他界面都不可交互的原因 (UIAlertView为1996,UIAlertSheet为2001)
方法
- (void)becomeKeyWindow; // 调用窗口,使之变成关键窗口(设置当前window变成主window)
- (void)resignKeyWindow; // 调用窗口,使之取消关键窗口(设置当前window变成主window)
- (void)makeKeyWindow; // 使之成为主窗口(让当前window变成keyWindow)
- (void)makeKeyAndVisible; // 使之成为主窗口,并且显示(让当前window变成keyWindow,并显示出来)
类的属性
@property(nonatomic,retain) UIViewController *rootViewController // 根控制器(设置UIViewController为根控制器)
// 当产生一个事件时,先传递给UIApplication,而UIAppliaction将这个事件传递UIWindow进行处理,然后由UIWindow将这个时间传递给特定的对象,即first responder,而UIWindow就是通过sendEvent寻找first responder,经过sendEvent分发到合适的对象,sendEvent就相当于时间的中转站。
- (void)sendEvent:(UIEvent *)event;
通知
// window变化的四个通知
UIKIT_EXTERN NSString *const UIWindowDidBecomeVisibleNotification; //当window显示就会调用
UIKIT_EXTERN NSString *const UIWindowDidBecomeHiddenNotification; //window被隐藏之后调用,需要注意的是,当程序进入后台时,这两个通知不会被调用,即使应用转到后台,窗口不会显示,窗口应用下的上下文中仍然被认为是可见的
UIKIT_EXTERN NSString *const UIWindowDidBecomeKeyNotification; //window成为主窗口调用
UIKIT_EXTERN NSString *const UIWindowDidResignKeyNotification; //window撤销主窗口调用
// 监听键盘变化的通知
UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification; //当键盘将要显示的时候调用
UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification; //当键盘已经显示的时候调用
UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification; //当键盘将要隐藏的时候调用
UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification; //当键盘隐藏完毕的时候调用
// 关于监听键盘通知的一些userInfo消息
UIKIT_EXTERN NSString *const UIKeyboardFrameBeginUserInfoKey NS_AVAILABLE_IOS(3_2); //动画前键盘的位置,包含CGRect的NSValue 可以在通知方法中写得到位置
CGRect rect = [[notif.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
UIKIT_EXTERN NSString *const UIKeyboardFrameEndUserInfoKey NS_AVAILABLE_IOS(3_2); //动画结束后键盘的位置 包含CGRect的NSValue
UIKIT_EXTERN NSString *const UIKeyboardAnimationDurationUserInfoKeyNS_AVAILABLE_IOS(3_0); //动画的持续时间,数值是NSNumber
UIKIT_EXTERN NSString *const UIKeyboardAnimationCurveUserInfoKey NS_AVAILABLE_IOS(3_0); //动画的曲线类型(UIViewAnimationCurve),数值是NSNumber
// 监听键盘frame大小变化的通知
UIKIT_EXTERN NSString *const UIKeyboardWillChangeFrameNotification NS_AVAILABLE_IOS(5_0); //当键盘frame值将要改变的时候调用
UIKIT_EXTERN NSString *const UIKeyboardDidChangeFrameNotification NS_AVAILABLE_IOS(5_0); //当键盘frame值已经改变的时候调用