深入了解iOS開(kāi)發(fā)中UIWindow的相關(guān)使用
UIWindow是一種特殊的UIView,通常在一個(gè)app中只會(huì)有一個(gè)UIWindow。
iOS程序啟動(dòng)完畢后,創(chuàng)建的第一個(gè)視圖控件就是UIWindow,接著創(chuàng)建控制器的view,最后將控制器的view添加到UIWindow上,于是控制器的view就顯示在屏幕上了。
一個(gè)iOS程序之所以能顯示到屏幕上,完全是因?yàn)樗蠻IWindow。也就說(shuō),沒(méi)有UIWindow,就看不見(jiàn)任何UI界面。
如何獲取UIWindow
(1)[UIApplication sharedApplication].windows 在本應(yīng)用中打開(kāi)的UIWindow列表,這樣就可以接觸應(yīng)用中的任何一個(gè)UIView對(duì)象(平時(shí)輸入文字彈出的鍵盤(pán),就處在一個(gè)新的UIWindow中);
(2)[UIApplication sharedApplication].keyWindow(獲取應(yīng)用程序的主窗口)用來(lái)接收鍵盤(pán)以及非觸摸類(lèi)的消息事件的UIWindow,而且程序中每個(gè)時(shí)刻只能有一個(gè)UIWindow是keyWindow;
注:經(jīng)過(guò)代碼驗(yàn)證,非keyWindow 也是可以接受鍵盤(pán)消息的;
提示:如果某個(gè)UIWindow內(nèi)部的文本框不能輸入文字,可能是因?yàn)檫@個(gè)UIWindow不是keyWindow;
(3)view.window獲得某個(gè)UIView所在的UIWindow。
UIWindowLevel
我們知道UIWindow 有三個(gè)層級(jí),分別是Normal ,StatusBar,Alert.輸出他們?nèi)齻€(gè)層級(jí)的值,我們發(fā)現(xiàn)從左到右依次是0,1000,2000,也就是說(shuō)Normal級(jí)別是最低的,StatusBar處于中級(jí),Alert級(jí)別最高。而通常我們的程序的界面都是處于Normal這個(gè)級(jí)別的,系統(tǒng)頂部的狀態(tài)欄應(yīng)該是處于StatusBar級(jí)別,UIActionSheet和UIAlertView這些通常都是用來(lái)中斷正常流程,提醒用戶等操作,因此位于Alert級(jí)別。
根據(jù)window顯示級(jí)別優(yōu)先原則,級(jí)別高的會(huì)顯示在最上層,級(jí)別低的在下面,我們程序正常顯示的view在最底層;
keyWindow
官方文檔中是這樣解釋的 “The key window is the one that is designated to receive keyboard and other non-touch related events. Only one window at a time may be the key window." 翻譯過(guò)來(lái)就是說(shuō),keyWindow是指定的用來(lái)接收鍵盤(pán)以及非觸摸類(lèi)的消息,而且程序中每一個(gè)時(shí)刻只能有一個(gè)window是keyWindow。
觀察UIWindow的文檔,我們可以發(fā)現(xiàn)里面有四個(gè)關(guān)于window變化的通知:
UIWindowDidBecomeVisibleNotification
UIWindowDidBecomeHiddenNotification
UIWindowDidBecomeKeyNotification
UIWindowDidResignKeyNotification
這四個(gè)通知對(duì)象中的object都代表當(dāng)前已顯示(隱藏),已變成keyWindow(非keyWindow)的window對(duì)象,其中的userInfo則是空的。于是我們可以注冊(cè)這個(gè)四個(gè)消息,再打印信息來(lái)觀察keyWindow的變化以及window的顯示,隱藏的變動(dòng)
變成keywindow 的流程是這樣的
1.程序默認(rèn)的window先顯示出來(lái)
2.默認(rèn)的window再變成keywindow
3.AlertView 的window顯示出來(lái)
4.默認(rèn)的window變成keywindow
5.最終AlertView的window變成keywindow
iOS8開(kāi)始UIWindow的bounds發(fā)生變化(Window本身發(fā)生了旋轉(zhuǎn))
iOS 7之前Window的bounds不會(huì)隨著方向而變化,但是到了iOS 8以后,隨著設(shè)備方向的旋轉(zhuǎn),window.bounds.size.width和window.bounds.size.height也會(huì)相應(yīng)發(fā)生變化。
做個(gè)很簡(jiǎn)單的測(cè)試,代碼如下:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
return YES;
}
- (void)orientationChanged:(NSNotification*)noti {
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
NSString *orientationDes = nil;
switch (orientation) {
case UIDeviceOrientationLandscapeLeft:
orientationDes = @"UIInterfaceOrientationLandscapeRight";
break;
case UIDeviceOrientationLandscapeRight:
orientationDes = @"UIInterfaceOrientationLandscapeLeft";
break;
case UIDeviceOrientationPortrait:
orientationDes = @"UIInterfaceOrientationPortrait";
break;
case UIDeviceOrientationPortraitUpsideDown:
orientationDes = @"UIInterfaceOrientationPortraitUpsideDown";
break;
default:
orientationDes = @"";
break;
}
NSLog(@"system ver: %@, \rorientaion: %@, \rwindow bounds: %@",
[UIDevice currentDevice].systemVersion,
orientationDes,
NSStringFromCGRect(self.window.bounds));
}
示例代碼很簡(jiǎn)單,新建一個(gè)工程,然后在delegate中直接添加以上代碼即可。
iOS 8上運(yùn)行結(jié)果為:
2014-06-04 09:26:32.016 SviOS8[4143:61114] system ver: 8.0,
orientaion: UIInterfaceOrientationLandscapeRight,
window bounds: {{0, 0}, {320, 480}}
2014-06-04 09:26:34.788 SviOS8[4143:61114] system ver: 8.0,
orientaion: UIInterfaceOrientationPortrait,
window bounds: {{0, 0}, {480, 320}}
2014-06-04 09:26:35.791 SviOS8[4143:61114] system ver: 8.0,
orientaion: UIInterfaceOrientationLandscapeLeft,
window bounds: {{0, 0}, {320, 480}}
2014-06-04 09:26:47.468 SviOS8[4143:61114] system ver: 8.0,
orientaion: UIInterfaceOrientationPortraitUpsideDown,
window bounds: {{0, 0}, {480, 320}}
iOS 7及之前的版本運(yùn)行結(jié)果為:
orientaion: UIInterfaceOrientationLandscapeRight,
window bounds: {{0, 0}, {320, 480}}
2014-06-04 09:39:00.895 SviOS8[4380:70b] system ver: 7.0.3,
orientaion: UIInterfaceOrientationPortrait,
window bounds: {{0, 0}, {320, 480}}
2014-06-04 09:39:01.225 SviOS8[4380:70b] system ver: 7.0.3,
orientaion: UIInterfaceOrientationLandscapeLeft,
window bounds: {{0, 0}, {320, 480}}
2014-06-04 09:39:11.004 SviOS8[4380:70b] system ver: 7.0.3,
orientaion: UIInterfaceOrientationPortraitUpsideDown,
window bounds: {{0, 0}, {320, 480}}
通過(guò)對(duì)比我們可以清晰的看到iOS 8中UIWindow在處理旋轉(zhuǎn)時(shí)策略的變更,雖然會(huì)因?yàn)榕c之前的版本不同導(dǎo)致現(xiàn)有項(xiàng)目布局存在的bug,但是可以看到iOS 8中的處理方式更加符合我們的預(yù)期,在豎向的時(shí)候我們就獲取到width < height, 在橫向則是 width > height,這個(gè)符合所見(jiàn)即所得的原則。
題外話,不管是iOS 7還是之前的版本,以及最新出的iOS 8,所有的ViewController的bounds都是正確的,所以只需要堅(jiān)持一個(gè)原則“所有布局都是基于VC.view.bounds布局,那么你的App的顯示就一切正常?!?br />
相關(guān)文章
Objective-C實(shí)現(xiàn)冒泡排序算法的簡(jiǎn)單示例
冒泡排序即是依次比較相鄰的兩個(gè)數(shù),如果后面的數(shù)較小則交換到前面一個(gè)數(shù)的位置上,這里我們來(lái)看一下Objective-C實(shí)現(xiàn)冒泡排序算法的簡(jiǎn)單示例2016-06-06iOS 條碼及二維碼掃描(從相冊(cè)中讀取條形碼/二維碼)及掃碼過(guò)程中遇到的坑
本文主要給大家介紹ios中從手機(jī)相冊(cè)中讀取條形碼和二維碼的問(wèn)題及解決辦法,需要的朋友參考下2017-01-01iOS App設(shè)計(jì)模式開(kāi)發(fā)中對(duì)迭代器模式的使用示例
這篇文章主要介紹了iOS App設(shè)計(jì)模式開(kāi)發(fā)中對(duì)迭代器模式的使用示例,示例代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-03-03iOS push側(cè)滑返回功能實(shí)現(xiàn)方法
這篇文章主要為大家詳細(xì)介紹了iOS push側(cè)滑返回功能實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05iOS封裝倒計(jì)時(shí)按鈕HLCountDownButton示例詳解
這篇文章主要為大家介紹了iOS封裝倒計(jì)時(shí)按鈕HLCountDownButton示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07iOS實(shí)現(xiàn)手勢(shì)滑動(dòng)解鎖功能簡(jiǎn)析
本篇文章主要介紹了iOS實(shí)現(xiàn)手勢(shì)滑動(dòng)解鎖功能簡(jiǎn)析,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10iOS開(kāi)發(fā)中使用FMDB來(lái)使程序連接SQLite數(shù)據(jù)庫(kù)
這篇文章主要介紹了iOS開(kāi)發(fā)中使用FMDB來(lái)使程序連接SQLite數(shù)據(jù)庫(kù),SQLite是一個(gè)簡(jiǎn)單的嵌入式數(shù)據(jù)庫(kù),非常適合輕量級(jí)使用,需要的朋友可以參考下2015-11-11