概述
想必做iOS的人都知道,我们的App是通过UIWindow这个载体呈现出来的。默认情况下,iOS App对于开发者来说只有一个UIWindow
,也就是AppDelegate在applicationDidFinishLaunching
里面创建出来的。
但是即使我们什么都不做,在我们的APP里面也会有其他的UIWindow
:
- 键盘对应的UITextEffectWindow
- 状态栏对应的UIStatusBarWindow(准确来说这个Window并不隶属于我们的App)
只不过上述两种UIWindow
我们一般不太容易去操作罢了,因此很多问题都无形被掩盖住了。最近正好需要做双十一晚会一个和横屏界面相关的需求,在整个过程中,发现了不少问题,所以接下来我们就说说如果在多个UIWindow状态下存在的一些问题吧。
那么在什么情况下会导致我们想要创建多UIWindow
的状态呢?我总结了一下,包括但不限于:
- 全局性的自定义HUD,Alert效果(SCAlert)等等。
- 需要展示的界面需要盖住UIStatusBar。
其中,第一种需求其实不一定需要创建一个新的UIWindow
实例,我们也可以将这些自定义的全局性界面添加到AppDelegate的window上。但是这样就会产生一个问题,由于在iOS8之前,UIWindow的bounds是不会随着旋转而改变的,拿到的永远是处于Portrait模式下的坐标系坐标。因此,对于直接添加在UIWindow上的视图,我们需要自己根据 UIApplicationDidChangeStatusBarOrientationNotification
来进行转换处理。
苹果这篇Q&A讲述了比较具体的原因:UIWindow并不会处理rotation事件,而是UIWindow的rootViewController去处理。
而对于第二种问题,添加一个盖在UIStatusBar上的界面,就必须依赖我们自己创建一个新的UIWindow,究其原因在于UIStatusBar本身并不属于我们App内可控的一个控件,而是一个系统级创建出来的产物。
因此,我们必须创建一个WindowLevel大于UIWindowStatusBar的新Window盖在上面才行。
有人会问:咦,奇怪了,为什么你在自己App内添加一个WindowLevel大于statusbar的就可以了呢?你只是在你自身应用内添加了一个UIView(UIWindow的子类),竟然能影响系统级的控件?
不知道大家有没有了解过CALayer
这层有个属性叫zPosition。通过操纵这个属性,我们可以调整视图渲染的前后关系。即使有的UIView在构建层级树的时候被后加的UIView所遮盖,但是在构建