UIWindow

一、簡介

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

<<UIWindow :UIWindow是一種特殊的UIView,通常在一個app中只會有一個UIWindow

<<繼承關系:UIWindow --> UIView?-->UIResponder-->NSObject

<<它包含了應用中的可見內容;

<<它在視圖和應用對象之間傳遞觸摸事件中起很重要的作用;

<<它和視圖控制器配合完成方向轉變

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

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

格式為

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

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

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

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

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

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

1、InterfaceBuilder創(chuàng)建UIWindow

用IB創(chuàng)建window非常簡單,因為Xcode的工程模板可以替你你創(chuàng)建。每個應用都會包含一個主XIB文件,這個XIB就包含了一個主window。另外,這些模板也為window在應用的代理對象中定義了outlet,你可以在代碼中通過outlet取到window對象。

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

??? 如果你重構代碼時用到 IB添加window,也很簡單,像XIB文件中拖一個window對象,然后進行如下操作:

要在運行時訪問window,應該把window和outlet相連。outlet一般情況下是在application delegate中,也可以是這個NIB文件對應的代碼文件。

重構過程中如果需要新建一個主NIB,那就得在info.plist文件中設置NSMainNibFil鍵。通過設置NSMainNibFil的值來確保這個window在代理方法application:didFinishLaunchingWithOptions:被調用是得到加載。

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



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

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

三、將view添加到UIWindow

1、直接將控制器的view添加到UIWindow中,并不理會它對應的控制器

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

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

2、設置uiwindow的根控制器,自動將rootviewcontroller的view添加到window中,負責管理rootviewcontroller的生命周期

[self.window.rootviewcontroller=vc];

rootViewController時UIWindow的一個遍歷方法,通過設置該屬性為要添加view對應的ViewController,UIWindow將會自動將其view添加到當前window中,同時負責ViewController和view的生命周期的維護,防止其過早釋放


<注意>建議使用(2).因為方法(1)存在一些問題,比如說控制器上面可能由按鈕,需要監(jiān)聽按鈕的點擊事件,如果是1,那么按鈕的事件應該由控制器來進行管理。但控制器是一個局部變量,控制器此時已經(jīng)不存在了,但是控制器的view還在,此時有可能會報錯。注意:方法執(zhí)行完,這個控制器就已經(jīng)不存在了。

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

問題描述2:添加一個開關按鈕,讓屏幕360度旋轉(兩者的效果不一樣)。當發(fā)生屏幕旋轉事件的時候,UIapplication對象會將旋轉事件傳遞給uiwindow,uiwindow又會將旋轉事件傳遞給它的根控制器,由根控制器決定是否需要旋轉

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

提示:不通過控制器的view也可以做開發(fā),但是在實際開發(fā)中,不要這么做,不要直接把view添加到UIWindow上面去。因為,難以管理。

四、獲取window

1、主窗口和次窗口

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

? ?因為Window有makekeyandvisible這個方法,可以讓這個Window憑空的顯示出來,而其他的view沒有這個方法,所以它只能依賴于Window,Window顯示出來后,view才依附在Window上顯示出來。

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

2.獲取UIwindow

1)[UIApplication?sharedApplication].windows ?在本應用中打開的UIWindow列表,這樣就可以接觸應用中的任何一個UIView對象(平時輸入文字彈出的鍵盤,就處在一個新的UIWindow中)

(2)[UIApplication sharedApplication].keyWindow(獲取應用程序的主窗口)用來接收鍵盤以及非觸摸類的消息事件的UIWindow,而且程序中每個時刻只能有一個UIWindow是keyWindow。

提示:如果某個UIWindow內部的文本框不能輸入文字,可能是因為這個UIWindow不是keyWindow

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

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

1-->設置Screen

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

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

2-->設置視圖層級

self.window.windowLevel = UIWindowLevelAlert+1;

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

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

? ? ? ? ? ? ? ? const ? UIWindowLevel UIWindowLevelNormal; 默認為0????

    const UIWindowLevel UIWindowLevelAlert;默認為2000

    const UIWindowLevel UIWindowLevelStatusBar;默認為1000

    typedef CGFloat UIWindowLevel;

Normal ,StatusBar,Alert.輸出他們三個層級的值,我們發(fā)現(xiàn)從左到右依次是0,1000,2000,也就是說Normal級別是最低的,StatusBar處于中級,Alert級別最高。而通常我們的程序的界面都是處于Normal這個級別的,系統(tǒng)頂部的狀態(tài)欄應該是處于StatusBar級別,提醒用戶等操作位于Alert級別。根據(jù)window顯示級別優(yōu)先原則,級別高的會顯示在最上層,級別低的在下面,我們程序正常顯示的view在最底層;

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

BOOL ?isKeyWindow=self.window.keyWindow;

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

4-->becomeKeyWindow

- (void)becomeKeyWindow; //該方法不應該被手動調用,當window變?yōu)閗eyWindow時會被自動調用來通知window。可以繼承UIWindow重寫此方法來實現(xiàn)功能

5-->resignKeyWindow

- (void)resignKeyWindow;?// 該方法不應該被手動調用,當window不再是keyWindow時(例如其他window實例調用了- makeKeyWindow或- makeKeyAndVisible方法)會被自動調用來通知window??梢岳^承UIWindow重寫此方法來實現(xiàn)功能。

6-->讓當前UIWindow變成keyWindow,默認不顯示

??[self.window?makeKeyWindow];

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

7-->讓當前UIWindow變成keyWindow,并顯示出來

?[self.window?makeKeyAndVisible];

- (void)makeKeyAndVisible;// ?讓當前UIWindow變成keyWindow,并顯示出來

8-->設置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調用window的該方法給window分發(fā)事件,window再將事件分發(fā)到合適的目標,比如將觸摸事件分發(fā)到真正觸摸的view上??梢灾苯诱{用該方法分發(fā)自定義事件。

10-->把該window中的一個坐標轉換成在目標window中時的坐標值

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

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

11-->把目標window中的一個坐標轉換成在該window中時的坐標值

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

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

12-->把該window中的一個矩陣轉換成在目標window中時的矩陣值

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

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

13--> 把目標window中的一個矩陣轉換成在該window中時的矩陣值

?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)測window的通知名稱:

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

UIKIT_EXTERN NSString *const UIWindowDidBecomeHiddenNotification;? // 當window隱藏的時候觸發(fā),暫時沒有實際測,返回空

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

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

3-->監(jiān)測鍵盤的通知名稱:

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

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

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

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

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

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

4-->userInfo字典中key為:

NSString *const UIKeyboardFrameBeginUserInfoKey;//userInfo字典里該key對應一個NSValue,存儲一個包含鍵盤初始frame值的CGRect結構(即鍵盤剛出現(xiàn)時的frame值)

NSString *const UIKeyboardFrameEndUserInfoKey;//userInfo字典里該key對應一個NSValue,存儲一個包含鍵盤結束frame值的CGRect結構(即鍵盤動畫結束后的frame值)

NSString *const UIKeyboardAnimationDurationUserInfoKey;//userInfo字典里該key對應一個NSNumber,存儲一個包含鍵盤進入或離開屏幕的UIViewAnimationCurve結構

NSString *const UIKeyboardAnimationCurveUserInfoKey;//userInfo字典里該key對應一個NSNumber,存儲一個包含鍵盤動畫時間的double值,時間以秒為單位。

例如,在UIKeyboardWillShowNotification,UIKeyboardDidShowNotification通知中的userInfo內容為

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鍵盤通知與鍵盤定制

UIKit-UIWindow詳解

UIWindow 詳解及使用場景

【iOS】UIWindow中文詳解

IOS學習記錄 基礎類UIWindow,UIView,UISreen篇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

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

友情鏈接更多精彩內容