UIWindow是我们必不可少的类,可能使用的较少,但是一个项目中少它不行,因为它是我们最顶层的界面容器,我们自己的相关的ViewController都要最终放到window.rootController中。一班情况UIWindow作为顶层容器的存在。
介绍下UIWindow的一个属性,windowLevel。
苹果文档中windowLevel有三种形式,并且是CGFloat类型的
UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert;
UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar __TVOS_PROHIBITED;
它们的值可以分别通过打印来验证
NSLog(@"%f %f %f",UIWindowLevelNormal,UIWindowLevelAlert,UIWindowLevelStatusBar);
0.000000 2000.000000 1000.000000
这个属性是干啥的
也就是可以通过这个属性来判断是不是优先显示UIWindow。默认的window的windowLevel是UIWindowLevelNormal,也就是0;
下面我们通过小Demo进行验证
1、首先验证苹果头文件中的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);
验证结果
UIWindowLevelNormal = 0.000000 UIWindowLevelAlert = 2000.000000 UIWindowLevelStatusBar = 1000.000000 appDelegate.window.windowLevel = 0.000000
2、验证系统通过UIWindow的windowLevel大小不同优先显示不同的UIWindow
需要注意的是,UIWindow的创建和UIView不同,UIWindow一旦被创建他就会添加到整个界面上。
如果你创建的UIWindow没有显示,请参考:
http://www.jianshu.com/p/75befce85623
创建不同的windowLevel查看相关的效果,代码如下
#import "ViewController.h"
@interface ViewController ()
// 创建属性
@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.
// 创建测试按钮
UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
tempBtn.frame = CGRectMake(100, 100, 100, 100);
tempBtn.backgroundColor = [UIColor cyanColor];
// 通过按钮的点击事件生成不同windowLevel级别的window
[tempBtn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:tempBtn];
}
按钮的单击事件调用test1
创建一个比默认window的windowLevel大的window来看一下什么效果,效果是会盖在原来的window上面
/**
* 这个方法证明两个问题
*1、创建 window 不用添加到任何的控件上面,直接创建完毕就能添加
*2、创建一个比默认window的windowLevel大的window来看一下什么效果,效果是会盖在原来的window上面
*/
- (void)test1
{
// 创建window
if (self.myWindow1 == nil) {
self.myWindow1 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIButton *windowBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[windowBtn setTitle:@"window1点我隐藏" 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];
}
// 设置window的颜色,这里设置成半透明的,方便查看window的层级关系
self.myWindow1.backgroundColor = [UIColor colorWithRed:0.00f green:1.00f blue:0.01f alpha:0.50f];
// 设置 window 的 windowLevel
self.myWindow1.windowLevel = 100;
self.myWindow1.hidden = NO;
}
效果图:
Paste_Image.png
按钮的单击事件调用test2
创建一个和默认window的windowLevel一样大的window来看一下什么效果,效果是会盖在原来的window上面
/**
* 这个方法证明两个问题
*1、创建 window 不用添加到任何的控件上面,直接创建完毕就能添加
*2、创建一个和默认window的windowLevel一样大的window来看一下什么效果,效果是会盖在原来的window上面
*/
- (void)test2
{
// 创建window
if (self.myWindow2 == nil) {
self.myWindow2 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIButton *windowBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[windowBtn setTitle:@"window2点我隐藏" 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];
}
// 设置window的颜色,这里设置成半透明的,方便查看window的层级关系
self.myWindow2.backgroundColor = [UIColor colorWithRed:0.91f green:0.13f blue:0.13f alpha:0.50f];
// 设置 window 的 windowLevel,设置的和当前存在的window一样
self.myWindow2.windowLevel = self.view.window.windowLevel;
self.myWindow2.hidden = NO;
[self.myWindow2 makeKeyAndVisible];
}
效果图
Paste_Image.png
按钮的单击事件调用test3
创建一个和默认window的windowLevel一样大的window来看一下什么效果,效果是会在在原来的window下面
/**
* 这个方法证明两个问题
*1、创建 window 不用添加到任何的控件上面,直接创建完毕就能添加
*2、创建一个和默认window的windowLevel一样大的window来看一下什么效果,效果是会在在原来的window下面
*/
- (void)test3
{
// 为了展示相关的效果,把当前的window的透明度设置为0.5
self.view.window.alpha = 0.5;
// 创建window
if (self.myWindow3 == nil) {
self.myWindow3 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
// 设置window的颜色,这里设置成半透明的,方便查看window的层级关系
self.myWindow3.backgroundColor = [UIColor blueColor];
// 设置 window 的 windowLevel,设置的比当前存在的window的小
self.myWindow3.windowLevel = -1;
self.myWindow3.hidden = NO;
[self.myWindow3 makeKeyAndVisible];
}
执行效果:
Paste_Image.png
调用完test方法可以查看当前一共有几个window,并且查看当前的测试window有没有实例化成功,所有的实例化的window并且声明周期够长,可以在[UIApplication sharedApplication].windows找到。
// 查看当前所有的window
NSLog(@"当前所有的window = %@ \nself.myWindow1 = %@",[UIApplication sharedApplication].windows,self.myWindow3);
通过以上总结如下:
1、UIWindowLevel的值不仅仅只有UIWindowLevelNormal、UIWindowLevelAlert、UIWindowLevelStatusBar 这三个,可以通过test3看出,只要你想可以是随意值,负数都可以。
2、UIWindow的显示的确可以通过UIWindowLevel来区分优先级,所有的window都会被加在界面上,只不过会通过优先级罗列起来,UIWindowLevel大的在上面显示,UIWindowLevel小的在下面显示。
3、UIWindowLevel优先级相等的情况下,看谁后实例化了,谁后实例化谁先显示
说了这么多了,有啥应用场景吗?
我想到的有如下场景
1、可以看到蚂蚁聚宝app每次压入后台的时候上面都有一层毛玻璃,我觉得可以用一个window搞一下。
2、其实系统的UIAlertView弹框的显示就是在自己创建的一个Window上面显示的<可以用alertView.window和当前的window比较,发现不是一个window,并且alertView.window.windowLevel大于0>,那么自定义的弹框或者其他也可以通过这个思路来搞一下。并且可以随时随地的销毁获取。
3、或者说每次有单独显示的界面也可以搞个window
代码链接参考:https://github.com/RunOfTheSnail/UIWindowDemo001
以上是我自己根据相关的运行效果总结的,如果有哪位大神觉得有地方描述的不准确,欢迎指正哈,在下感激不尽!!!
还有其他的应用的话欢迎补充。
网友评论
removeWindow,这个方法就是你在D中发出的通知方法,在创建Window的VC中响应。
- (void)removeWindow
{
self.myWindow3.hidden = YES;
self.myWindow3 = nil;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"\n\n\n\n 333当前所有的window = %@ \nself.myWindow1 = %@",[UIApplication sharedApplication].windows,self.myWindow3);
});
}
你可以试一下。
+(UIViewController*)getRootViewController
{
UIWindow *window=[[UIApplication sharedApplication]keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
UINavigationController *nc=(UINavigationController*) window.rootViewController;
return nc.visibleViewController;
}
得到根控制器 如果Level有负数的话 这样得到的能是最下面的window吗
http://www.jianshu.com/p/ae84cd31d8f0,你看下这个。看看能不能解决你的问题。