- 父类是UIView,它是一个特别的UIView
- 每个App至少有一个UIWindow,是第一个创建的视图控件。
UIApplication中的窗口及其层级
- 设置窗口的层级,层级谁大就显示在最外面
窗口的层级 | 代表窗口 | 层级 |
---|---|---|
UIWindowLevelNormal | 默认窗口的层级(含主窗口) | 低 |
UIWindowLevelStatusBar | 键盘;状态栏(无法通过application.windows打印显示,原因是它没有交给application管理) | 中 |
UIWindowLevelAlert | UIActionSheet,UIAlearView | 高 |
// 窗口的层级本质是枚举值(数字),数字越大,层级越高
self.window1.windowLevel = UIWindowLevelAlert
self.window2.windowLevel = UIWindowLevelAlert + 1 //显示在最外层
UIWindow创建
- 创建时间:程序启动完毕的时候才创建
- 创建方式:
- 系统自动创建窗口详见UIStoryboard中
系统加载指定storyboard的流程
通过storyboard加载程序,窗口都交给系统创建及管理,不需要我们管理 - 代码创建(常用):
步骤:
1. 创建窗口
2. 加载根控制器
3. 设置窗口的根控制器,显示窗口// 在开发中通常在程序启动完成的时候手动创建窗口 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // 1.创建窗口 // self -> AppDelegate self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; // 1.1设置颜色(可选) // self.window.backgroundColor = [UIColor yellowColor]; // 2.创建根控制器,在设置窗口的根控制器 UIViewController *vc = [[UIViewController alloc] init]; self.window.rootViewController = vc; // 3.显示窗口 [self.window makeKeyAndVisible]; return YES; }
- 系统自动创建窗口详见UIStoryboard中
UIWindow的常用方法
// 让当前UIWindow变成keyWindow(主窗口)
[window makeKeyWindow];
// 让当前UIWindow变成keyWindow,并显示出来(hidden属性为NO)
// 注意,若再创建一个window,调用makeKeyAndVisible方法,并不会使之前的window隐藏
[window makeKeyAndVisible];
// 在本应用中打开的UIWindow列表
// 这样就可以接触应用中的任何一个UIView对象(平时输入文字弹出的键盘,就处在一个新的UIWindow中)
NSLog(@"%@",[UIApplication sharedApplication].windows);
// 用来接收键盘以及非触摸类的消息事件的UIWindow
// 程序中每个时刻只能有一个UIWindow是keyWindow
[UIApplication sharedApplication].keyWindow
//获得某个UIView所在的UIWindow,可用于判断是否已加入到控件中,避免重复添加
if (view.window) return;
窗口与根控制器
- 设置窗口的根控制器,底层会自动把根控制器的view添加到窗口上,并且让控制器的view有旋转功能
为什么要用根控制器开发,没有跟控制器一样能显示界面。
原因:
1. 开发中会存在很多界面,为了管理方便,通常一个界面交给一个控制器管理,逻辑清晰
2. 控制器有专门的view生命周期方法,用于处理UIView遇到的事件
3. 若直接通过addSubView将控制器的view添加到窗口中,控制器会被释放,控制器就不能处理事件,另外控制器的view不会自动旋转。每个控制器的view都是懒加载的,所以不要在窗口中设置根控制器view的属性;而应该在根控制器中设置
切换根控制器的常见用处:
当新特性界面展示完成,切换到主界面,这时只需要切换根控制器,新特性界面就会自动销毁,显示主界面。IOS9之后必须在
程序启动完毕那一刻
显示出来的窗口必须
要设置根控制器
;IOS9之前不尽然
UIWindow的内存管理与显示注意细节
一定要强引用窗口
1. 必须设置AppDelegate.window = window,这样会被AppDelegate用强指针指向,不会被释放;
2. 如果不设置AppDelegate.window,直接让新创建的window成为主窗口并显示,结果是黑屏;通过自定义窗口在dealloc中打印语句,检测结果是:窗口销毁了必须有尺寸
建议与屏幕同宽同高-
成为主窗口,或设置hidden属性为NO
[window makeKeyAndVisible]; // window.hidden = NO
4. 经过前3步,窗口已经在应用程序显示,但所有UIView默认颜色是clearColor,只有设置其他颜色才能被我们发现
1. 若没有设置颜色,也没有其他控件显示,最终显示的是屏幕(屏幕颜色是黑色,所以肉眼所见就是黑色)
2. 应用程序显示从内到外是:屏幕->主窗口->根控制的View->子控件(或子控件的子控件...)。最终显示的是最外层控件
5. 存在多个窗口时,预期的窗口没有出现,检查窗口的层级
,判断是否被其他窗口遮挡
### 窗口->主窗口时间
* 应用程序自动加载,新建的窗口成为主窗口时间:是在根控制器的View完成显示时,测试时间及结果如下:
```objc
// 测试时间1:控件加载中
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"keywindow%@---%@",[UIApplication sharedApplication].keyWindow,[UIApplication sharedApplication].windows);
}
// 测试时间2:控件即将显示
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSLog(@"keywindow%@---%@",[UIApplication sharedApplication].keyWindow,[UIApplication sharedApplication].windows);
}
// 测试时间3:控件已经显示
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(@"keywindow%@---%@",[UIApplication sharedApplication].keyWindow,[UIApplication sharedApplication].windows);
}
```
```objc
// viewDidLoad打印结果
keywindow(null)---
(
"<UIWindow: 0x7f86b0e6d4c0; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7f86b0e6e830>; layer = <UIWindowLayer: 0x7f86b0e6a250>>"
)
// viewWillAppear打印结果
keywindow(null)---
(
"<UIWindow: 0x7f86b0e6d4c0; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7f86b0e6e830>; layer = <UIWindowLayer: 0x7f86b0e6a250>>"
)
// viewDidAppear打印结果
keywindow<UIWindow: 0x7f86b0e6d4c0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f86b0e6e830>; layer = <UIWindowLayer: 0x7f86b0e6a250>>---
(
"<UIWindow: 0x7f86b0e6d4c0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7f86b0e6e830>; layer = <UIWindowLayer: 0x7f86b0e6a250>>"
)
```