UIWindows简介
- 1. UIwindow的文档
- 2. 获取UIwindow
- 3. 把view添加到uiwindow
- 4. 那么在哪些场合会涉及到“手工创建UIWindow”呢?
- 5. 有storyboard的项目中,UIWindow是如何创建的
UIWindow是一种特殊的UIView,通常在一个程序中只会有一个UIWindow,但可以手动创建多个UIWindow,同时加到程序里面。UIWindow在程序中主要起到三个作用:
- 作为容器,包含app所要显示的所有视图
- 传递触摸消息到程序中view和其他对象
- 与UIViewController协同工作,方便完成设备方向旋转的支持
1. 看一下UIwindow的文档:
NOTE
- 当使用 storyboard 时,已经自动帮你创建Windows对象了
- 当你使用 Interface Builder 时,需要在Launch option中设置全屏( Full Screen )选项
- 和创建UIView不同,UIWindow一旦被创建,它就自动地被添加到整个界面上了(UIWindow实例没能正常显示的原因是因为Window的hidden默认值为true,或者level不够高)
Configuring Windows
@property(nonatomic) UIWindowLevel windowLevel
- UIWindow在显示的时候会根据UIWindowLevel进行排序的,即Level高的将排在所有Level比他低的层级的前面。
- 默认为 0.0
- 还有三个特殊值:
UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;
0.000000UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;
2000.000000UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar __TVOS_PROHIBITED;
1000.000000
@property(nonatomic, strong) UIScreen *screen
- 显示当前Window的UIScreen对象
- 默认一般只有唯一的设备屏幕 (mac可以外接显示器,手机行吗?)
@property(nonatomic, strong) UIViewController *rootViewController
- 默认为nil,(代码创建 或者使用 interface builder都可以为它赋值)
- 若当前window已经保持了一个 view树,设置新值时,旧view树会被移除
Making Windows Key
@property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow
- 判断该windows是否是应用的keyWindow
- keyWindow 能接收键盘或者其他 non-touch相关事件
- 只有一个windows能作为keywindow
- (void)makeKeyAndVisible
- 使Window成为 key windows,并且在相同或者低level之前展示
- (void)becomeKeyWindow
- 当window成为 key window 时,该方法会被调用
- 同时会发送
UIWindowDidBecomeKeyNotification
到默认通知中心 - 不要自己直接调用这个方法
- (void)makeKeyWindow
- (void)resignKeyWindow
- 与 becomeKeyWindow 相对应,当window让出 keywindow 时会被调用
- 会发送
UIWindowDidResignKeyNotification
到默认通知中心
Converting Coordinates
// 跳过
Sending Events
- (void)sendEvent:(UIEvent *)event
- UIApplication 对象将分派事件 发送到相应的views ?
2. 获取UIwindow
2.1获取UIWindow列表
[UIApplication sharedApplication].windows
获取在应用中打开的UIWindow列表,可以获取应用中的任何一个UIView对象,例如 当输入文字时,弹出的键盘就是UIWindow,如果需要改变键盘的样式,则可用更改当前Window
2.2获取当前主窗口
[UIApplication sharedApplication].keyWindow
获取应用程序的主窗口,用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是keyWindow。
注意:如果UIWindow内部的文本框不能输入文字,可能是因为这个UIWindow不是keyWindow
2.3获取当前view 所在的UIWindow
view.window
获得某个UIView所在的UIWindow
3. 把view添加到uiwindow
创建一个控制器,把view添加到uiwindow上面(有两种方式)
-
直接将控制器的view添加到UIWindow中,并不理会它对应的控制器
[self.window addsubview:vc.view];
-
设置uiwindow的根控制器,自动将rootviewcontroller的view添加到window中,负责管理rootviewcontroller的生命周期
[self.window.rootviewcontroller=vc];
3.1两个方法的区别:
以后的开发中,建议使用(2).因为方法(1)存在一些问题,比如说控制器上面可能由按钮,需要监听按钮的点击事件,如果是1,那么按钮的事件应该由控制器来进行管理。但控制器是一个局部变量,控制器此时已经不存在了,但是控制器的view还在,此时有可能会报错。注意:方法执行完,这个控制器就已经不存在了。
问题描述1:当view发生一些事件的时候,通知控制器,但是控制器已经销毁了,所以可能出现未知的错误。
问题描述2:添加一个开关按钮,让屏幕360度旋转(两者的效果不一样)。当发生屏幕旋转事件的时候,UIapplication对象会将旋转事件传递给uiwindow,uiwindow又会将旋转事件传递给它的根控制器,由根控制器决定是否需要旋转
UIapplication->uiwindow->根控制器(第一种方式没有根控制器,所以不能跟着旋转)。
提示:不通过控制器的view也可以做开发,但是在实际开发中,不要这么做,不要直接把view添加到UIWindow上面去。因为,难以管理
4. 那么在哪些场合会涉及到“手工创建UIWindow”呢?
参考唐巧在《iOS开发进阶》里的描述,我认为支付宝钱包等App的密码保护页面是基于UIWindow实现的,当用户从应用的任何界面按Home键退出,过一段时间再从后台切换回来时,显示一个密码输入界面。只有用户输入了正确的密码,才能进入退出前的界面。因为这个密码输入界面可能从任何应用界面弹出,并且需要盖住所有界面的最上层,所以很合适做一个UIWindow来实现。
其他适合用UIWindow来实现的功能还包括:应用的启动介绍页,应用内的通知提醒消息,应用内的弹出框广告等。
5.在有storyboard的项目中,UIWindow是如何创建的?
有storyboard的项目中的创建过程:
当用户点击应用程序图标的时候,先执行Main函数,执行UIApplicationMain(),根据其第三个和第四个参数创建Application,创建代理,并且把代理设置给application(看项目配置文件info.plist里面的storyboard的name,根据这个name找到对应的storyboard),开启一个事件循环,当程序加载完毕,
他会调用代理的didFinishLaunchingWithOptions:方法。在调用didFinishLaunchingWithOptions:方法之前,会加载storyboard,在加载的时候创建一个window,接下来会创建箭头所指向的控制器,把该控制器设置为UIWindow的根控制器,接下来再将window显示出来,即看到了运行后显示的界面。(提示:关于这部分可以查看story的初始化的文档)