UIWindow深度學(xué)習(xí)系列——windowLevel屬性

UIWindow

???UIWindow是我們必不可少的系統(tǒng)類,因?yàn)樗钦麄€(gè)App的界面容器,重要性不言而喻。本文介紹下UIWindow的一個(gè)屬性,windowLevel。
蘋(píng)果文檔中windowLevel有三種形式,并且是CGFloat類型的

UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar __TVOS_PROHIBITED;

它們的值可以分別通過(guò)打印來(lái)驗(yàn)證

NSLog(@"%f  %f  %f",UIWindowLevelNormal,UIWindowLevelAlert,UIWindowLevelStatusBar);

0.000000 2000.000000 1000.000000

???鍵盤(pán)Window:經(jīng)常用的彈出鍵盤(pán),其實(shí)也是一個(gè)UIWindow,蘋(píng)果沒(méi)有列出,也沒(méi)有相關(guān)的公開(kāi)API調(diào)用。但是我們可以利用模擬器跑demo彈出鍵盤(pán)時(shí),打開(kāi)xcode的圖層查看器,你會(huì)發(fā)現(xiàn)有三個(gè)Window層級(jí)(其實(shí)還有一個(gè)statusBarWindow看不到),UIwindow是我們 keywindow,UItextEffectsWindow(文本效果窗口,如毛玻璃效果),UIRemoteKeyboardWindow(這個(gè)類是調(diào)用不到)。它們的windowLevel分別是

0.000000   1.000000 1000000.000000

???你沒(méi)看錯(cuò),鍵盤(pán)Window的WindowLevel是100萬(wàn)級(jí),最高級(jí)。

???iOS10.3 新出了一個(gè)window類,是邀請(qǐng)?jiān)u價(jià)的彈窗,這是個(gè)極度隱秘的視圖。用Xcode跑圖層,是看不到這個(gè)邀請(qǐng)?jiān)u價(jià)彈窗視圖的,用代碼打印Windows數(shù)組也是拿不到的視圖,蘋(píng)果用心之良苦啊,根本無(wú)從檢測(cè)是否真正彈出這個(gè)邀請(qǐng)?jiān)u價(jià)!邀請(qǐng)?jiān)u價(jià)每年3次機(jī)會(huì),是調(diào)用接口的三次有效機(jī)會(huì),用完3次再次調(diào)用不起作用!

???ps:UItextEffectsWindow 是iOS8 新特性,部分說(shuō)法,鍵盤(pán)Window是在UItextEffectsWindow上,說(shuō)法是不對(duì)的,即使不彈出鍵盤(pán),也會(huì)有 UItextEffectsWindow,只是在該Windows上還有個(gè)view來(lái)標(biāo)識(shí)鍵盤(pán)位置而已,UItextEffectsWindow和UIRemoteKeyboardWindow是兩個(gè)window。

???UIwindow都是繼承自UIview的 你也可以自定義視圖addsubview到鍵盤(pán)的window上。

這個(gè)屬性是干啥的?

windowLevel

也就是可以通過(guò)這個(gè)屬性來(lái)判斷是不是優(yōu)先顯示UIWindow。默認(rèn)的window的windowLevel是UIWindowLevelNormal,也就是0;
下面我們通過(guò)小Demo進(jìn)行驗(yàn)證
1、首先驗(yàn)證蘋(píng)果頭文件中的UIWindow的windowLevel是多少

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSLog(@"UIWindowLevelNormal = %f  UIWindowLevelAlert = %f  UIWindowLevelStatusBar = %f  appDelegate.window.windowLevel = %f",UIWindowLevelNormal,UIWindowLevelAlert,UIWindowLevelStatusBar,appDelegate.window.windowLevel);

驗(yàn)證結(jié)果

UIWindowLevelNormal = 0.000000  UIWindowLevelAlert = 2000.000000  UIWindowLevelStatusBar = 1000.000000  appDelegate.window.windowLevel = 0.000000

2、驗(yàn)證系統(tǒng)通過(guò)UIWindow的windowLevel大小不同優(yōu)先顯示不同的UIWindow
需要注意的是,UIWindow的創(chuàng)建和UIView不同,UIWindow一旦被創(chuàng)建他就會(huì)添加到整個(gè)界面上。
如果你創(chuàng)建的UIWindow沒(méi)有顯示,請(qǐng)參考:
http://www.itdecent.cn/p/75befce85623

創(chuàng)建不同的windowLevel查看相關(guān)的效果,代碼如下

#import "ViewController.h"
@interface ViewController ()
// 創(chuàng)建屬性
@property (nonatomic, strong)UIWindow *myWindow1;
@property (nonatomic, strong)UIWindow *myWindow2;
@property (nonatomic, strong)UIWindow *myWindow3;
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    // 創(chuàng)建測(cè)試按鈕
    UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    tempBtn.frame = CGRectMake(100, 100, 100, 100);
    tempBtn.backgroundColor = [UIColor cyanColor];
    // 通過(guò)按鈕的點(diǎn)擊事件生成不同windowLevel級(jí)別的window
    [tempBtn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:tempBtn];
}

按鈕的單擊事件調(diào)用test1
創(chuàng)建一個(gè)比默認(rèn)window的windowLevel大的window來(lái)看一下什么效果,效果是會(huì)蓋在原來(lái)的window上面

/**
 *  這個(gè)方法證明兩個(gè)問(wèn)題
 *1、創(chuàng)建 window 不用添加到任何的控件上面,直接創(chuàng)建完畢就能添加
 *2、創(chuàng)建一個(gè)比默認(rèn)window的windowLevel大的window來(lái)看一下什么效果,效果是會(huì)蓋在原來(lái)的window上面
 */
- (void)test1
{
    // 創(chuàng)建window
    if (self.myWindow1 == nil) {
        self.myWindow1 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

        UIButton *windowBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [windowBtn setTitle:@"window1點(diǎn)我隱藏" forState:UIControlStateNormal];
        windowBtn.backgroundColor = [UIColor redColor];
        windowBtn.frame = CGRectMake(100, 300, 100, 100);
        [windowBtn addTarget:self action:@selector(clickWindowBtn:) forControlEvents:UIControlEventTouchUpInside];
        [self.myWindow1 addSubview:windowBtn];

    }
    // 設(shè)置window的顏色,這里設(shè)置成半透明的,方便查看window的層級(jí)關(guān)系
    self.myWindow1.backgroundColor = [UIColor colorWithRed:0.00f green:1.00f blue:0.01f alpha:0.50f];
    // 設(shè)置 window 的 windowLevel
    self.myWindow1.windowLevel = 100;
    self.myWindow1.hidden = NO;
}
效果圖1

按鈕的單擊事件調(diào)用test2
創(chuàng)建一個(gè)和默認(rèn)window的windowLevel一樣大的window來(lái)看一下什么效果,效果是會(huì)蓋在原來(lái)的window上面

/**
 *  這個(gè)方法證明兩個(gè)問(wèn)題
 *1、創(chuàng)建 window 不用添加到任何的控件上面,直接創(chuàng)建完畢就能添加
 *2、創(chuàng)建一個(gè)和默認(rèn)window的windowLevel一樣大的window來(lái)看一下什么效果,效果是會(huì)蓋在原來(lái)的window上面
 */
- (void)test2
{
    // 創(chuàng)建window
    if (self.myWindow2 == nil) {
        self.myWindow2 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

        UIButton *windowBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [windowBtn setTitle:@"window2點(diǎn)我隱藏" forState:UIControlStateNormal];
        windowBtn.backgroundColor = [UIColor greenColor];
        windowBtn.frame = CGRectMake(100, 300, 200, 100);
        [windowBtn addTarget:self action:@selector(clickWindow2Btn:) forControlEvents:UIControlEventTouchUpInside];
        [self.myWindow2 addSubview:windowBtn];

    }
    // 設(shè)置window的顏色,這里設(shè)置成半透明的,方便查看window的層級(jí)關(guān)系
    self.myWindow2.backgroundColor = [UIColor colorWithRed:0.91f green:0.13f blue:0.13f alpha:0.50f];

    // 設(shè)置 window 的 windowLevel,設(shè)置的和當(dāng)前存在的window一樣
    self.myWindow2.windowLevel = self.view.window.windowLevel;
    self.myWindow2.hidden = NO;
    [self.myWindow2 makeKeyAndVisible];
}
效果圖2

按鈕的單擊事件調(diào)用test3
創(chuàng)建一個(gè)和默認(rèn)window的windowLevel一樣大的window來(lái)看一下什么效果,效果是會(huì)在在原來(lái)的window下面

/**
 *  這個(gè)方法證明兩個(gè)問(wèn)題
 *1、創(chuàng)建 window 不用添加到任何的控件上面,直接創(chuàng)建完畢就能添加
 *2、創(chuàng)建一個(gè)和默認(rèn)window的windowLevel一樣大的window來(lái)看一下什么效果,效果是會(huì)在在原來(lái)的window下面
 */

- (void)test3
{
    // 為了展示相關(guān)的效果,把當(dāng)前的window的透明度設(shè)置為0.5
    self.view.window.alpha = 0.5;

    // 創(chuàng)建window
    if (self.myWindow3 == nil) {
        self.myWindow3 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    }
    // 設(shè)置window的顏色,這里設(shè)置成半透明的,方便查看window的層級(jí)關(guān)系
    self.myWindow3.backgroundColor = [UIColor blueColor];

    // 設(shè)置 window 的 windowLevel,設(shè)置的比當(dāng)前存在的window的小
    self.myWindow3.windowLevel = -1;
    self.myWindow3.hidden = NO;
    [self.myWindow3 makeKeyAndVisible];
}
執(zhí)行效果

調(diào)用完test方法可以查看當(dāng)前一共有幾個(gè)window,并且查看當(dāng)前的測(cè)試window有沒(méi)有實(shí)例化成功,所有的實(shí)例化的window并且聲明周期夠長(zhǎng),可以在[UIApplication sharedApplication].windows找到。

// 查看當(dāng)前所有的window
NSLog(@"當(dāng)前所有的window = %@ \nself.myWindow1 = %@",[UIApplication sharedApplication].windows,self.myWindow3);

通過(guò)以上總結(jié)如下
1、UIWindowLevel的值不僅僅只有UIWindowLevelNormal、UIWindowLevelAlert、UIWindowLevelStatusBar 這三個(gè),可以通過(guò)test3看出,只要你想可以是隨意值,負(fù)數(shù)都可以。
2、UIWindow的顯示的確可以通過(guò)UIWindowLevel來(lái)區(qū)分優(yōu)先級(jí),所有的window都會(huì)被加在界面上,只不過(guò)會(huì)通過(guò)優(yōu)先級(jí)羅列起來(lái),UIWindowLevel大的在上面顯示,UIWindowLevel小的在下面顯示。
3、UIWindowLevel優(yōu)先級(jí)相等的情況下,看誰(shuí)后實(shí)例化了,誰(shuí)后實(shí)例化誰(shuí)先顯示

說(shuō)了這么多了,有啥應(yīng)用場(chǎng)景嗎?
我想到的有如下場(chǎng)景
1、可以看到螞蟻聚寶app每次壓入后臺(tái)的時(shí)候上面都有一層毛玻璃,我覺(jué)得可以用一個(gè)window搞一下。
2、其實(shí)系統(tǒng)的UIAlertView彈框的顯示就是在自己創(chuàng)建的一個(gè)Window上面顯示的<可以用alertView.window和當(dāng)前的window比較,發(fā)現(xiàn)不是一個(gè)window,并且alertView.window.windowLevel大于0>,那么自定義的彈框或者其他也可以通過(guò)這個(gè)思路來(lái)搞一下。并且可以隨時(shí)隨地的銷毀獲取。
3、或者說(shuō)每次有單獨(dú)顯示的界面也可以搞個(gè)window

以上是我自己根據(jù)相關(guān)的運(yùn)行效果總結(jié)的,還有其他的應(yīng)用的話歡迎補(bǔ)充。

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容