一 UIWindow 简介

UIWindow  是特殊的 UIView ,通常一个App中只有UIWindows,当程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的UIView,将控制器的View添加到UIWindow上,控制器的 UIView 就显示在屏幕上。注意 UIWindow 本身不做显示,是控制器的UIView做展示,UIWindow 会给视图分发事件。




1.1 程序加载示意图

ios oc tabbar中间悬浮按钮_导航栏




1.2 UIWindow作用

1.UIWindow作为一个容器,容纳所有的UIView

2.UIWindow会其他事件消息传递给UIWiew





二 UIWindow 使用

//在 prefix_AppDelegate.h 文件中,默认有UIWindow 的属性,可用直接在prefix_AppDelegate.m 中使用
@property (strong, nonatomic) UIWindow *window;
 
//1 创建 UIWindow 
self.window = [[UIWindow alloc]init];

//2 设置控制器,并设置UIWindow的根控制器
UIViewController *vc = [[UIViewController alloc]init];
vc.view.backgroundColor = [UIColor redColor];
self.window.rootViewController = vc;

//3 显示UIWindow
[self.window makeKeyAndVisible];
//在 prefix_AppDelegate.h 文件中,默认有UIWindow 的属性,可用直接在prefix_AppDelegate.m 中使用
@property (strong, nonatomic) UIWindow *window;
 
//1 创建 UIWindow 
self.window = [[UIWindow alloc]init];

//2 设置控制器,并设置UIWindow的根控制器
UIViewController *vc = [[UIViewController alloc]init];
vc.view.backgroundColor = [UIColor redColor];
self.window.rootViewController = vc;

//3 显示UIWindow
[self.window makeKeyAndVisible];






三 UIWindow 属性方法说明

//default is [UIScreen mainScreen]. changing the screen may be an expensive operation and should not be done in performance-sensitive code
//默认是 [UIScreen mainScreen],改变屏幕是消息性能的操作,不应该写对性能敏感的代码
@property(nonatomic,retain) UIScreen *screen NS_AVAILABLE_IOS(3_2);  

//UIWindow在显示的时候会根据UIWindowLevel进行排序的,即Level高的将排在所有Level比他低的层级的前面。
@property(nonatomic) UIWindowLevel windowLevel;                   // default = 0.0 即Normal

//是否是主窗口
@property(nonatomic,readonly,getter=isKeyWindow) BOOL keyWindow;

//根控制器
@property(nonatomic,retain) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0);  // default is nil

//调用窗口,使成为主窗口
- (void)becomeKeyWindow;                             

//调用窗口,取消成为主窗口
- (void)resignKeyWindow;                             

//将当前 UIWindow 设置成应用的 key window,但并不显示
- (void)makeKeyWindow;

//将当前 UIWindow 设置成应用的 key window,并显示
- (void)makeKeyAndVisible;
//default is [UIScreen mainScreen]. changing the screen may be an expensive operation and should not be done in performance-sensitive code
//默认是 [UIScreen mainScreen],改变屏幕是消息性能的操作,不应该写对性能敏感的代码
@property(nonatomic,retain) UIScreen *screen NS_AVAILABLE_IOS(3_2);  

//UIWindow在显示的时候会根据UIWindowLevel进行排序的,即Level高的将排在所有Level比他低的层级的前面。
@property(nonatomic) UIWindowLevel windowLevel;                   // default = 0.0 即Normal

//是否是主窗口
@property(nonatomic,readonly,getter=isKeyWindow) BOOL keyWindow;

//根控制器
@property(nonatomic,retain) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0);  // default is nil

//调用窗口,使成为主窗口
- (void)becomeKeyWindow;                             

//调用窗口,取消成为主窗口
- (void)resignKeyWindow;                             

//将当前 UIWindow 设置成应用的 key window,但并不显示
- (void)makeKeyWindow;

//将当前 UIWindow 设置成应用的 key window,并显示
- (void)makeKeyAndVisible;





3.1 windowLevel  属性说明

UIWindowLevel 类型,多个 UIWindow 的显示顺序是按照 windowLevel 从高到低排列的,windowLevel 最高的显示在最前面。UIWindowLevel 类型的定义如下:

const UIWindowLevel UIWindowLevelNormal;       //The default level. 默认等级
const UIWindowLevel UIWindowLevelAlert;        //The level for an alert view. alert view等级
const UIWindowLevel UIWindowLevelStatusBar;    //The level for a status window. 状态栏等级
typedef CGFloat UIWindowLevel;
const UIWindowLevel UIWindowLevelNormal;       //The default level. 默认等级
const UIWindowLevel UIWindowLevelAlert;        //The level for an alert view. alert view等级
const UIWindowLevel UIWindowLevelStatusBar;    //The level for a status window. 状态栏等级
typedef CGFloat UIWindowLevel;

等级顺序为:

UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert

所以当创建额外的 UIWindow,并需要 UIWindow 显示在 UIAlertView 的前面,可以将此 windowLevel 设置为大于UIWindowLevelAlert的数(UIWindowLevelAlert+1),UIWindow 将显示在 UIAlertView 前面。

如果多个UIWindow UIWindowLevel相同,先调用 makeKeyAndVisble 者的会一直显示在前面。





3.2 makeKeyAndVisible 和 makeKeyWindow 方法区别

[self.window makeKeyAndVisible]让窗口成为主窗口,并且显示出来,才能把信息显示到屏幕上。

因为Window有makeKeyAndVisible这个方法,可以让这个Window凭空的显示出来,而其他的view没有这个方法,所以它只能依赖于Window,Window显示出来后,view才依附在Window上显示出来。

[self.window makeKeyWindow]让uiwindow成为主窗口,但不显示。

注意:keyWindow 用来接受键盘 非触摸事件,不是keyWindow 就不能接受键盘事件





3.3 获取UIwindow



3.3.1 获取UIWindow列表

[UIApplication sharedApplication].windows  获取在应用中打开的UIWindow列表,可以获取应用中的任何一个UIView对象,例如 当输入文字时,弹出的键盘就是UIWindow,如果需要改变键盘的样式,则可用更改当前Window




3.3.2 获取当前主窗口

[UIApplication sharedApplication].keyWindow获取应用程序的主窗口,用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是keyWindow。

注意:如果UIWindow内部的文本框不能输入文字,可能是因为这个UIWindow不是keyWindow




3.3.3 获取当前view 所在的UIWindow

view.window获得某个UIView所在的UIWindow





四 UIWindow rootViewController 属性

@property(nonatomic,retain) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0);  // default is nil
@property(nonatomic,retain) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0);  // default is nil

rootViewController 属性,是iOS 4.0新增属性,设置此属性后,rootViewController 所包含的 view 将被添加到 UIWindow 中,iOS 4.0之前版本可采用 addSubview: 方法达到同样的效果,因为 UIWindow 类本身就是 UIView 的子类,但两种方式有着本质的区别.




4.1 UIView 添加到 UIWindow 的两种方式



4.1.1 addsubview

[self.window  addSubview:vc.view],直接将控制器的view添加到UIWindow中,并能接受控制器的事件




4.1.2 rootviewcontroller

[self.window.rootViewController=vc]; 设置UIWindow的根控制器,自动将rootviewcontroller的view添加到window中,负责管理rootviewcontroller的生命周期





4.2 addSubview 和 rootViewController 区别

[window addSubview:vc.view] 添加控制的弊端:

1. 弱引用,当view发生一些事件的时候,通知控制器,但是控制器已经销毁了,报野指针错误

2. 屏幕旋转时导航栏和添加控件不能旋转  (IOS8 测试,并没出现这种情况,是不是IOS8解决着问题了?知道的大拿,回复下)

原因:

事件处理机制:检测事件->UIApplication->UIWindow->rootViewController ,通过[window addSubview] 方式因为没有设置根控制器,所以导航栏和控件接收不到事件







五 实例



5.1 代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    //1.创建 UIWindow 属性
    self.window = [[UIWindow alloc]init];
    self.window.frame = [UIScreen mainScreen].bounds;
    
    //2.设置背景色
    self.window.backgroundColor = [UIColor greenColor];
    
    //3.创建控制器
    UIViewController *vc = [[UIViewController alloc]init];
    vc.view.backgroundColor = [UIColor redColor];
    //3.1 控制器添加按钮
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [vc.view addSubview:btn];
    
    //4.控制器添加到 UIWindow 上
    /*
        [window addSubview:vc.view] 添加 控制的弊端
        1.弱引用,当发生事件时,报野指针错误
        2.屏幕旋转时导航栏和添加控件不能旋转
        事件处理机制:
        检测事件->UIApplication->UIWindow->rootViewController
        
        通过[window addSubview] 方式因为没有设置根控制器,所以导航栏和控件接收不到事件
     */
    //[window addSubview:vc.view];
    self.window.rootViewController = vc;
    
    
    //4.显示UIWindow
    /*
        4.1 makeKeyAndVisible 方法
        让window 称为主要的window,并显示
        
        keyWindow 用来接受键盘 非触摸事件,不是keyWindow 就不能接受键盘事件
     */
    [self.window makeKeyAndVisible];
    
    
    //4.2 makeKeyWindow 方法
    //让window 称为主要的window,但并不显示
    //[window makeKeyWindow]
    
    
    //5 获取程序中的keyWindow
    [UIApplication sharedApplication].keyWindow;
    return YES;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    //1.创建 UIWindow 属性
    self.window = [[UIWindow alloc]init];
    self.window.frame = [UIScreen mainScreen].bounds;
    
    //2.设置背景色
    self.window.backgroundColor = [UIColor greenColor];
    
    //3.创建控制器
    UIViewController *vc = [[UIViewController alloc]init];
    vc.view.backgroundColor = [UIColor redColor];
    //3.1 控制器添加按钮
    UIButton *btn = [UIButton buttonWithType:UIButtonTypeContactAdd];
    [vc.view addSubview:btn];
    
    //4.控制器添加到 UIWindow 上
    /*
        [window addSubview:vc.view] 添加 控制的弊端
        1.弱引用,当发生事件时,报野指针错误
        2.屏幕旋转时导航栏和添加控件不能旋转
        事件处理机制:
        检测事件->UIApplication->UIWindow->rootViewController
        
        通过[window addSubview] 方式因为没有设置根控制器,所以导航栏和控件接收不到事件
     */
    //[window addSubview:vc.view];
    self.window.rootViewController = vc;
    
    
    //4.显示UIWindow
    /*
        4.1 makeKeyAndVisible 方法
        让window 称为主要的window,并显示
        
        keyWindow 用来接受键盘 非触摸事件,不是keyWindow 就不能接受键盘事件
     */
    [self.window makeKeyAndVisible];
    
    
    //4.2 makeKeyWindow 方法
    //让window 称为主要的window,但并不显示
    //[window makeKeyWindow]
    
    
    //5 获取程序中的keyWindow
    [UIApplication sharedApplication].keyWindow;
    return YES;
}