好久沒有更新博客了O.O因?yàn)樽罱ぷ骱妹AT
當(dāng)然忙的時候也積累了很多以前沒注意的問題鹰贵。所以又有了很多能寫成博客的素材O.O
所以這次先來研究一下我以前從來沒注意過的UIWindow好了。
Window的作用
在iOS中街佑,一個window(也就是一個UIWindow對象)主要有這樣幾個作用:
- 展示app的可視內(nèi)容狼速;
- 將事件分發(fā)給視圖以及其他對象骂倘;
- 和app的view controller一起處理屏幕旋轉(zhuǎn)变姨。
其實(shí)在大多數(shù)情況下盖矫,第三方程序員不用做任何事情,window就能完成這些工作群凶。所以很多時候插爹,只有當(dāng)這個app需要支持另一個外設(shè)的屏幕的時候哄辣,程序員才會對window進(jìn)行操作请梢。
創(chuàng)建window
有好幾種創(chuàng)建window的方式:
使用storyboard:
如果程序員為app創(chuàng)建了一個storyboard赠尾,并在info.plist中指定它為main storyboard,那么在app啟動的時候毅弧,iOS會自動幫程序員做這樣幾件事情:
- 實(shí)例化一個window气嫁;
- 加載main storyboard,并且實(shí)例化其中的root view controller够坐;
- 將這個view controller賦值給window.rootViewController寸宵,并顯示這個window。
使用nib文件:
如果不使用storyboard元咙,也可以用nib文件來代替梯影。將一個window對象拖拽到Interface Builder文件中,并將這個文件指定為app的main interface庶香。那么在app啟動的時候甲棍,iOS也會自動創(chuàng)建window對象。
為了確保window的大小與屏幕大小吻合赶掖,需要在Interface Builder中對window對象勾選Full Screen at Launch這個屬性感猛。
手寫代碼:
當(dāng)然也可以通過手寫代碼的方式創(chuàng)建window。比如官方示例代碼:
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
myViewController = [[MyViewController alloc] init];
window.rootViewController = myViewController;
[window makeKeyAndVisible];
return YES;
}
需要注意的是奢赂,window的尺寸永遠(yuǎn)應(yīng)該是屏幕的尺寸陪白,不應(yīng)該考慮狀態(tài)欄等元素,因?yàn)檫@些是view controller應(yīng)該處理的問題膳灶。
Action Sheet和Alert View
知道了window的存在之后咱士,感覺也能知道很多事情。
比如轧钓,iOS中的UIActionSheet和UIAlertView其實(shí)是顯示在另一個window上的司致。
監(jiān)聽UIWindowDidResignKeyNotification
,可以發(fā)現(xiàn)聋迎,當(dāng)action sheet彈出時脂矫,UIWindowDidResignKeyNotification
通知被發(fā)送了。此時檢查app所在的window霉晕,發(fā)現(xiàn)它已經(jīng)不再是key window了庭再。
懸浮窗
以前我總以為所有的view都是被拘束在UIViewController的view中的,所以一直不知道懸浮窗的效果應(yīng)該如何實(shí)現(xiàn)牺堰。但實(shí)際上拄轻,UIWindow本身就是一個UIView,可以直接在UIWindow上添加子視圖伟葫,做出懸浮的效果恨搓。(雖然這樣不符合蘋果的設(shè)計(jì)規(guī)范)
[[[UIApplication sharedApplication].delegate window] addSubview:suspendView];
呈現(xiàn)出視圖懸浮在app之上的效果:
黑科技?
好奇嘗試了一些奇怪的情景O.O
如果window沒有占滿整個屏幕會怎樣呢?
默認(rèn)情況下斧抱,window中的視圖依然能照常顯示常拓,但是觸屏事件無法正常分發(fā)。
官方文檔中這樣描述:
Because a window doesn’t receive touch events outside of its bounds and views aren’t clipped to the window’s bounds by default, an improperly sized window might not be able to deliver touch events to all its views.
用手寫代碼的方式可以創(chuàng)建一個任意大小的window辉浦,比如在application:willFinishLaunchingWithOptions:
方法中寫:
self.window = [[XSQWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
運(yùn)行程序時弄抬,window中的子視圖依然可以照常顯示,包括window外的部分宪郊,但是在點(diǎn)擊window之外的區(qū)域時掂恕,終端會輸出錯誤信息:
unexpected nil window in _UIApplicationHandleEventFromQueueEvent, _windowServerHitTestWindow: <XSQWindow: 0x14c614a20; baseClass = UIWindow; frame = (0 0; 200 200); gestureRecognizers = <NSArray: 0x174059740>; layer = <UIWindowLayer: 0x174220e60>>
并且觸屏點(diǎn)對應(yīng)的視圖無法接收到這次的觸屏事件。
如果在一個app中創(chuàng)建多個window會怎么樣弛槐?
也是可以做到在一個app中創(chuàng)建多個window的懊亡,而且似乎也不會怎么樣。
觸屏事件會根據(jù)觸摸點(diǎn)的位置乎串,被UIApplication分發(fā)到對應(yīng)的window中斋配。
參考
UIWindow Class Reference
Understanding Windows and Screens
iOS開發(fā)UI篇—控制器的創(chuàng)建
關(guān)于UIWindow的一點(diǎn)兒思考
Event Delivery: The Responder Chain