作者刘文涛
转载请注明出处
UIWindow简介
在iOS应用中,我们使用UIWindow和UIView来呈现界面。UIWindow是最顶层的界面容器。UIWindow并不包含任何默认的内容,但是它被当做UIView的容器,用于放置应用中的所有UIView。而每一个UIView通常都用来表示具体的某一部分界面,例如一段文字、一张图片等。当然你可以用UIView来当做其他UIView的容器。所以UIWindow更多的时候只是作为UIView的顶层容器存在。
NS_CLASS_AVAILABLE_IOS(2_0) @interface UIWindow : UIView
在继承关系上,我们能看到UIWindow继承自UIView,所以UIWindow除了具有UIView的功能外,还增加了一些特有的属性和方法。
而我们最常用的方法就是在程序刚启动时,调用UIWindow的makeKeyAndVisible方法,使整个程序界面可见,代码如下所示:
|
|
所以UIWindow的主要作用有:
1.做完UIView的最顶层容器,包含应用显示所需要的所有UIView。
2.传递触摸消息和键盘事件给UIView。
为UIWindow增加UIView
通常我们有两种方法给UIWindow增加子UIView:
1.通过调用addSubView方法。因为UIWindow是UIView的子类,所以它可以使用UIView的addSubView方法给自己增加子VIew,从而承担容器的作用。
2.通过设置其特有的rootViewController属性。通过设置该属性为要添加view对应的UIViewController,UIWindow将会自动将其view添加到当前window中,同时负责维护VIewController和view的生命周期。我们在之前的application: didFinishLaunchingWithOptions:示例代码中看到的就是这种方法。
系统对UIWindow的使用
通常在一个程序中只会有一个UIWindow,但是有些时候我们调用系统的控件(例如UIAlertView)时,iOS系统为了保证UIAlertView在所有的界面之上,他会临时创建一个新的UIWindow,通过将其UIWindow的UIWindowLevel设置的更高,让UIAlertView盖在所有的应用界面之上。
为了验证这一说法,我们创建了一个新的测试Xcode工程,在其主ViewController上添加一个button,点击button弹出一个系统的弹框。示例代码:
|
|
WindowLevel
那么是不是新创建的UIWindow一定会在界面的最上层呢?其实不是这样的。UIWindow有一个WindowLevel的属性该属性定义了UIWindow的层级,系统定义的WindowLevel一共有三种取值:
|
|
我们将这些值通过代码打印输出:
|
|
输出的结果:
2017-06-06 11:43:09.345 UIWindowDemo[899:667871] UIWindowLevelNormal=0.000000
2017-06-06 11:43:09.346 UIWindowDemo[899:667871] UIWindowLevelAlert=2000.000000
2017-06-06 11:43:09.346 UIWindowDemo[899:667871] UIWindowLevelStatusBar=1000.000000
从中我们可以看出来默认程序的UIWindow的层级是UIWindowLevelNormal,当系统需要在上面覆盖UIAlertView时,就会创建一个层级是UIWindowLevelAlert的UIWindow,因为其WindowLevel的值更高,所以就覆盖在上面了。
在实际应用中,WindowLevel的取值并不限于上面提到的3个值。
手动创建UIWindow
有些时候我们也希望在应用开发中,将某个界面覆盖在所有的界面最上层。这个时候我们就可以手动创建一个新的UIWindow。需要注意的是,和创建UIView不同,UIWindow一旦被创建,它就会自动被添加到整个界面上了。
例如想做一个密码保护功能,在用户按home键退出应用界面,过一段时间后从后台切换回来时,显示一个密码输入界面。用户只有输入正确的密码才能进入退出的前台界面。因为这个密码输入界面可能从任何应用界面弹出,并且需要遮在所有界面的最上层,所以它很适合用UIWindow来实现。