UIWindow

一、簡(jiǎn)介

<<UIWindow類(lèi)定義,管理和協(xié)調(diào)的Windows應(yīng)用程序顯示在屏幕上的對(duì)象(如Windows)。一個(gè)窗口的兩個(gè)主要職能是,為顯示其意見(jiàn)面積和分發(fā)活動(dòng)的意見(jiàn)。窗口是在視圖層次的根。一個(gè)窗口屬于一個(gè)級(jí)別;一個(gè)級(jí)別的窗口出現(xiàn)另一個(gè)層面以上。例如,警報(bào)出現(xiàn)高于正常的窗口。通常情況下,只有一個(gè)在IOS應(yīng)用程序的窗口

<<UIWindow :UIWindow是一種特殊的UIView,通常在一個(gè)app中只會(huì)有一個(gè)UIWindow

<<繼承關(guān)系:UIWindow --> UIView?-->UIResponder-->NSObject

<<它包含了應(yīng)用中的可見(jiàn)內(nèi)容;

<<它在視圖和應(yīng)用對(duì)象之間傳遞觸摸事件中起很重要的作用;

<<它和視圖控制器配合完成方向轉(zhuǎn)變

? ? ? 在iOS系統(tǒng)中,windows沒(méi)有標(biāo)題欄、關(guān)閉框以及其他可視控件。一個(gè)window就是一個(gè)或多個(gè)視圖的空白容器,而且應(yīng)用不能通過(guò)window來(lái)改變自己的顯示內(nèi)容。當(dāng)你想要改變現(xiàn)顯示容的時(shí)候,改變最上層的視圖就可以了。

?? ?大多數(shù)iOS應(yīng)用在其生命周期內(nèi)只使用一個(gè)window,這個(gè)window從應(yīng)用的主nib文件中加載,鋪滿整個(gè)主屏幕。當(dāng)然,如果你的應(yīng)用支持外部顯示,它會(huì)額外創(chuàng)建一個(gè)window,用于外部顯示。系統(tǒng)會(huì)創(chuàng)建其他典型的window,一般是在響應(yīng)特殊事件時(shí)創(chuàng)建,例如來(lái)電顯示。

格式為

1--> 設(shè)置根視圖(屬性的作用

[self.window.rootviewcontroller=vc];; ? (這是具體的例子

@property(nullable, nonatomic,strong) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0); // 設(shè)置根視圖,?默認(rèn)是空的 ??(這是屬性的說(shuō)明

二、UIWindow的創(chuàng)建和配置

可以代碼或者InterfaceBuilder來(lái)創(chuàng)建并設(shè)置window。您在啟動(dòng)時(shí)創(chuàng)建了窗口,并應(yīng)保留它,并將其保存到應(yīng)用程序代理對(duì)象中的引用。如果需要額外的window,則在需要用的時(shí)候創(chuàng)建即可。

??? 創(chuàng)建window不需要考慮應(yīng)用實(shí)在前臺(tái)啟動(dòng)還是后臺(tái)啟動(dòng)。創(chuàng)建和設(shè)置一個(gè)window不需要花太多資源。如果程序直接在后臺(tái)啟動(dòng),那么你就不能讓window可見(jiàn),直到window到前臺(tái)之后再讓其可見(jiàn)

1、InterfaceBuilder創(chuàng)建UIWindow

用IB創(chuàng)建window非常簡(jiǎn)單,因?yàn)閄code的工程模板可以替你你創(chuàng)建。每個(gè)應(yīng)用都會(huì)包含一個(gè)主XIB文件,這個(gè)XIB就包含了一個(gè)主window。另外,這些模板也為window在應(yīng)用的代理對(duì)象中定義了outlet,你可以在代碼中通過(guò)outlet取到window對(duì)象。

注意:在使用IB創(chuàng)建window的時(shí)候,應(yīng)該在屬性設(shè)置欄中設(shè)置為全屏。如果沒(méi)有設(shè)置為全屏,且window小于手機(jī)的屏幕尺寸,那么一些視圖的觸摸時(shí)間肯接收不到。這是因?yàn)閣indow接受不到自己區(qū)域以外的觸摸事件。如果視圖的觸摸點(diǎn)沒(méi)在window的區(qū)域范圍內(nèi),則響應(yīng)不到觸摸事件。所以要確保window是全屏。

??? 如果你重構(gòu)代碼時(shí)用到 IB添加window,也很簡(jiǎn)單,像XIB文件中拖一個(gè)window對(duì)象,然后進(jìn)行如下操作:

要在運(yùn)行時(shí)訪問(wèn)window,應(yīng)該把window和outlet相連。outlet一般情況下是在application delegate中,也可以是這個(gè)NIB文件對(duì)應(yīng)的代碼文件。

重構(gòu)過(guò)程中如果需要新建一個(gè)主NIB,那就得在info.plist文件中設(shè)置NSMainNibFil鍵。通過(guò)設(shè)置NSMainNibFil的值來(lái)確保這個(gè)window在代理方法application:didFinishLaunchingWithOptions:被調(diào)用是得到加載。

2、純代碼創(chuàng)建window



上面代碼中的self.window,是在application delegate中已經(jīng)聲明過(guò)得屬性,用來(lái)保存window對(duì)象。如果你創(chuàng)建的是用于外部顯示的window,應(yīng)該給它重新命名,并且需要設(shè)置bounds。

?創(chuàng)建window的時(shí)候,要把bounds設(shè)置為屏幕大小,不能有任何縮減

三、將view添加到UIWindow

1、直接將控制器的view添加到UIWindow中,并不理會(huì)它對(duì)應(yīng)的控制器

[self.window ?addsubview:vc.view];

直接將view通過(guò)addSubview方式添加到window中,程序負(fù)責(zé)維護(hù)view的生命周期以及刷新,但是并不會(huì)為去理會(huì)view對(duì)應(yīng)的ViewController,因此采用這種方法將view添加到window以后,我們還要保持view對(duì)應(yīng)的ViewController的有效性,不能過(guò)早釋放。

2、設(shè)置uiwindow的根控制器,自動(dòng)將rootviewcontroller的view添加到window中,負(fù)責(zé)管理rootviewcontroller的生命周期

[self.window.rootviewcontroller=vc];

rootViewController時(shí)UIWindow的一個(gè)遍歷方法,通過(guò)設(shè)置該屬性為要添加view對(duì)應(yīng)的ViewController,UIWindow將會(huì)自動(dòng)將其view添加到當(dāng)前window中,同時(shí)負(fù)責(zé)ViewController和view的生命周期的維護(hù),防止其過(guò)早釋放


<注意>建議使用(2).因?yàn)榉椒ǎ?)存在一些問(wèn)題,比如說(shuō)控制器上面可能由按鈕,需要監(jiān)聽(tīng)按鈕的點(diǎn)擊事件,如果是1,那么按鈕的事件應(yīng)該由控制器來(lái)進(jìn)行管理。但控制器是一個(gè)局部變量,控制器此時(shí)已經(jīng)不存在了,但是控制器的view還在,此時(shí)有可能會(huì)報(bào)錯(cuò)。注意:方法執(zhí)行完,這個(gè)控制器就已經(jīng)不存在了。

問(wèn)題描述1:當(dāng)view發(fā)生一些事件的時(shí)候,通知控制器,但是控制器已經(jīng)銷(xiāo)毀了,所以可能出現(xiàn)未知的錯(cuò)誤。

問(wèn)題描述2:添加一個(gè)開(kāi)關(guān)按鈕,讓屏幕360度旋轉(zhuǎn)(兩者的效果不一樣)。當(dāng)發(fā)生屏幕旋轉(zhuǎn)事件的時(shí)候,UIapplication對(duì)象會(huì)將旋轉(zhuǎn)事件傳遞給uiwindow,uiwindow又會(huì)將旋轉(zhuǎn)事件傳遞給它的根控制器,由根控制器決定是否需要旋轉(zhuǎn)

UIapplication->uiwindow->根控制器(第一種方式?jīng)]有根控制器,所以不能跟著旋轉(zhuǎn))。

提示:不通過(guò)控制器的view也可以做開(kāi)發(fā),但是在實(shí)際開(kāi)發(fā)中,不要這么做,不要直接把view添加到UIWindow上面去。因?yàn)椋y以管理。

四、獲取window

1、主窗口和次窗口

【self.window makekeyandvisible】讓窗口成為主窗口,并且顯示出來(lái)。有這個(gè)方法,才能把信息顯示到屏幕上。

? ?因?yàn)閃indow有makekeyandvisible這個(gè)方法,可以讓這個(gè)Window憑空的顯示出來(lái),而其他的view沒(méi)有這個(gè)方法,所以它只能依賴(lài)于Window,Window顯示出來(lái)后,view才依附在Window上顯示出來(lái)。

【self.window make keywindow】//讓uiwindow成為主窗口,但不顯示。

2.獲取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。

提示:如果某個(gè)UIWindow內(nèi)部的文本框不能輸入文字,可能是因?yàn)檫@個(gè)UIWindow不是keyWindow

(3)view.window獲得某個(gè)UIView所在的UIWindow

五、UIWindow的視圖屬性(屬性的順序與蘋(píng)果API一致)

1-->設(shè)置Screen

????????self.window.screen?=?self.externalScreen;??

@property(nonatomic,strong) UIScreen *screen NS_AVAILABLE_IOS(3_2);//默認(rèn)是[UIScreen mainScreen]。改變屏幕可能是一個(gè)昂貴的操作,不應(yīng)該在性能敏感的代碼中完成

2-->設(shè)置視圖層級(jí)

self.window.windowLevel = UIWindowLevelAlert+1;

@property(nonatomic) UIWindowLevel windowLevel; // 默認(rèn)為0

<注意>UIWindow在顯示的時(shí)候會(huì)根據(jù)UIWindowLevel進(jìn)行排序的,即Level高的將排在所有Level比他低的層級(jí)的前面。下面我們來(lái)看UIWindowLevel的定義:

? ? ? ? ? ? ? ? const ? UIWindowLevel UIWindowLevelNormal; 默認(rèn)為0????

    const UIWindowLevel UIWindowLevelAlert;默認(rèn)為2000

    const UIWindowLevel UIWindowLevelStatusBar;默認(rèn)為1000

    typedef CGFloat UIWindowLevel;

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í)別,提醒用戶等操作位于Alert級(jí)別。根據(jù)window顯示級(jí)別優(yōu)先原則,級(jí)別高的會(huì)顯示在最上層,級(jí)別低的在下面,我們程序正常顯示的view在最底層;

3-->是否為根視圖(只讀屬性)

BOOL ?isKeyWindow=self.window.keyWindow;

@property(nonatomic,readonly,getter=isKeyWindow) BOOL keyWindow;

4-->becomeKeyWindow

- (void)becomeKeyWindow; //該方法不應(yīng)該被手動(dòng)調(diào)用,當(dāng)window變?yōu)閗eyWindow時(shí)會(huì)被自動(dòng)調(diào)用來(lái)通知window。可以繼承UIWindow重寫(xiě)此方法來(lái)實(shí)現(xiàn)功能

5-->resignKeyWindow

- (void)resignKeyWindow;?// 該方法不應(yīng)該被手動(dòng)調(diào)用,當(dāng)window不再是keyWindow時(shí)(例如其他window實(shí)例調(diào)用了- makeKeyWindow或- makeKeyAndVisible方法)會(huì)被自動(dòng)調(diào)用來(lái)通知window。可以繼承UIWindow重寫(xiě)此方法來(lái)實(shí)現(xiàn)功能。

6-->讓當(dāng)前UIWindow變成keyWindow,默認(rèn)不顯示

??[self.window?makeKeyWindow];

- (void)makeKeyWindow;?//?讓window成為keyWindow(主窗口),默認(rèn)不可見(jiàn)

7-->讓當(dāng)前UIWindow變成keyWindow,并顯示出來(lái)

?[self.window?makeKeyAndVisible];

- (void)makeKeyAndVisible;// ?讓當(dāng)前UIWindow變成keyWindow,并顯示出來(lái)

8-->設(shè)置uiwindow的根控制器

[self.window.rootviewcontroller=vc];

@property(nullable, nonatomic,strong) UIViewController *rootViewController NS_AVAILABLE_IOS(4_0);// ?根控制器

9-->分發(fā)自定義事件

UIApplication 和 UIWindow 有方法 - sendEvent: ,用于把事件分發(fā)到 hitTest View

UIApplication == sendEvent: ==> UIWindow == sendEvent: ==> hitTest View

- (void)sendEvent:(UIEvent *)event;//UIApplication調(diào)用window的該方法給window分發(fā)事件,window再將事件分發(fā)到合適的目標(biāo),比如將觸摸事件分發(fā)到真正觸摸的view上。可以直接調(diào)用該方法分發(fā)自定義事件。

10-->把該window中的一個(gè)坐標(biāo)轉(zhuǎn)換成在目標(biāo)window中時(shí)的坐標(biāo)值

CGPoint p = [self.window1 convertPoint:CGPointMake(0, 0) toWindow:self.window0];

- (CGPoint)convertPoint:(CGPoint)point toWindow:(nullable UIWindow *)window;

11-->把目標(biāo)window中的一個(gè)坐標(biāo)轉(zhuǎn)換成在該window中時(shí)的坐標(biāo)值

CGPoint p = [self.window1 convertPoint:CGPointMake(0, 0) fromWindow:self.window0];

- (CGPoint)convertPoint:(CGPoint)point fromWindow:(UIWindow *)window;

12-->把該window中的一個(gè)矩陣轉(zhuǎn)換成在目標(biāo)window中時(shí)的矩陣值

CGRect rect=[self.window convertRect:CGRectMake(0, 0, 0, 0) toView:self.window0];

- (CGRect)convertRect:(CGRect)rect toWindow:(UIWindow *)window; ?

13--> 把目標(biāo)window中的一個(gè)矩陣轉(zhuǎn)換成在該window中時(shí)的矩陣值

?CGRect rect=[self.window convertRect:CGRectMake(0, 0, 0, 0) toView:self.window0];

- (CGRect)convertRect:(CGRect)rect fromWindow:(UIWindow *)window;

六、UIWindow的常量屬性

1-->UIWindowLevel的枚舉

UIWindowLevelNormal;// 0.000000

UIWindowLevelStatusBar;// 1000.000000

UIWindowLevelAlert;// 2000.000000

2-->監(jiān)測(cè)window的通知名稱(chēng):

UIKIT_EXTERN NSString *const UIWindowDidBecomeVisibleNotification; // 當(dāng)window激活時(shí)并展示在界面的時(shí)候觸發(fā),返回空

UIKIT_EXTERN NSString *const UIWindowDidBecomeHiddenNotification;? // 當(dāng)window隱藏的時(shí)候觸發(fā),暫時(shí)沒(méi)有實(shí)際測(cè),返回空

UIKIT_EXTERN NSString *const UIWindowDidBecomeKeyNotification;? ? // 當(dāng)window被設(shè)置為keyWindow時(shí)觸發(fā),返回空

UIKIT_EXTERN NSString *const UIWindowDidResignKeyNotification;? ? // 當(dāng)window的key位置被取代時(shí)觸發(fā),返回空

3-->監(jiān)測(cè)鍵盤(pán)的通知名稱(chēng):

UIKIT_EXTERN NSString *const UIKeyboardWillShowNotification;//?顯示鍵盤(pán)的時(shí)候立即發(fā)出該通知

UIKIT_EXTERN NSString *const UIKeyboardDidShowNotification;//顯示鍵盤(pán)后才發(fā)出該通知

UIKIT_EXTERN NSString *const UIKeyboardWillHideNotification;//鍵盤(pán)即將消失的時(shí)候立即發(fā)出該通知

UIKIT_EXTERN NSString *const UIKeyboardDidHideNotification;//鍵盤(pán)消失后才發(fā)出該通知

UIKIT_EXTERN NSString *const UIKeyboardWillChangeFrameNotification? NS_AVAILABLE_IOS(5_0);//鍵盤(pán)的frame值發(fā)生變化的時(shí)候立即發(fā)出該通知

UIKIT_EXTERN NSString *const UIKeyboardDidChangeFrameNotification? NS_AVAILABLE_IOS(5_0);//鍵盤(pán)的frame值發(fā)生變化后才發(fā)出該通知

4-->userInfo字典中key為:

NSString *const UIKeyboardFrameBeginUserInfoKey;//userInfo字典里該key對(duì)應(yīng)一個(gè)NSValue,存儲(chǔ)一個(gè)包含鍵盤(pán)初始frame值的CGRect結(jié)構(gòu)(即鍵盤(pán)剛出現(xiàn)時(shí)的frame值)

NSString *const UIKeyboardFrameEndUserInfoKey;//userInfo字典里該key對(duì)應(yīng)一個(gè)NSValue,存儲(chǔ)一個(gè)包含鍵盤(pán)結(jié)束frame值的CGRect結(jié)構(gòu)(即鍵盤(pán)動(dòng)畫(huà)結(jié)束后的frame值)

NSString *const UIKeyboardAnimationDurationUserInfoKey;//userInfo字典里該key對(duì)應(yīng)一個(gè)NSNumber,存儲(chǔ)一個(gè)包含鍵盤(pán)進(jìn)入或離開(kāi)屏幕的UIViewAnimationCurve結(jié)構(gòu)

NSString *const UIKeyboardAnimationCurveUserInfoKey;//userInfo字典里該key對(duì)應(yīng)一個(gè)NSNumber,存儲(chǔ)一個(gè)包含鍵盤(pán)動(dòng)畫(huà)時(shí)間的double值,時(shí)間以秒為單位。

例如,在UIKeyboardWillShowNotification,UIKeyboardDidShowNotification通知中的userInfo內(nèi)容為

userInfo = {

? ? UIKeyboardAnimationCurveUserInfoKey = 0;

? ? UIKeyboardAnimationDurationUserInfoKey = "0.25";

? ? UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}";

? ? UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}";

? ? UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}";

? ? UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}";

? ? UIKeyboardFrameChangedByUserInteraction = 0;

? ? UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}";

}

參考:

IOS: iPhone鍵盤(pán)通知與鍵盤(pán)定制

UIKit-UIWindow詳解

UIWindow 詳解及使用場(chǎng)景

【iOS】UIWindow中文詳解

IOS學(xué)習(xí)記錄 基礎(chǔ)類(lèi)UIWindow,UIView,UISreen篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • UIView的功能 負(fù)責(zé)渲染區(qū)域的內(nèi)容,并且響應(yīng)該區(qū)域內(nèi)發(fā)生的觸摸事件 UIWindow 在iOS App中,UI...
    小蘑菇2閱讀 796評(píng)論 4 5
  • 一、UIWindow是一種特殊的UIView,通常在一個(gè)app中只會(huì)有一個(gè)UIWindow。 iOS程序啟動(dòng)完畢后...
    MrLXQ閱讀 1,077評(píng)論 0 3
  • 每一個(gè)IOS程序都有一個(gè)UIWindow,在我們通過(guò)模板簡(jiǎn)歷工程的時(shí)候,xcode會(huì)自動(dòng)幫我們生成一個(gè)window...
    jumping鵬閱讀 1,084評(píng)論 0 0
  • 概念: UIWindw定義了一個(gè)負(fù)責(zé)管理,協(xié)調(diào)一個(gè)App的View是如何顯示在設(shè)備屏幕上的窗口類(lèi),除非一個(gè)App可...
    Harely閱讀 896評(píng)論 0 1
  • 170918【讀書(shū) day190】《與奇人相遇》 葛吉夫 45m 今天看的兩個(gè)章節(jié)中,描述了葛吉夫先生很多生意上的...
    水若_小水囈夢(mèng)閱讀 227評(píng)論 0 0