UIWindow

大多数人对于UIWindow都很熟悉,但又很不了解,这篇文章我们就谈谈UIWindow。UIWindow继承与UIView,我们创建的第一个视图控件就是UIWindow。

KeyWindow

一个APP可以拥有很多UIWindow,但是同一时间同一时刻,永远只能有一个KeyWindow,keyWindow是指定的用来接收键盘和其它非触摸事件。UIWindow创建出来默认是隐藏的,我们可以通过makeKeyAndVisible让其成为KeyWindow,该属性同时也将其hidden属性设置为NO。也可以分别设置,例如

1 [self.window makeKeyWindow];
2 self.window.hidden = NO;

如何创建一个UIWindow

先看看下面这段代码

1 - (void)btnClicked:(UIButton *)button
2 {
3     UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
4     window.backgroundColor = [UIColor redColor];
5     [window makeKeyAndVisible];
6 }

分析:当我们点击UIButton,出发该事件。但是我们发现,UIWindow没有生成,这是为什么呢?原因就在window创建在栈里,会很快被释放。正确的写法应该是这样,创建一个UIWindow的属性,如下,

1 -(void)btnClicked:(UIButton *)button
2 {
3     _window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
4     self.window.backgroundColor = [UIColor redColor];
5     [self.window makeKeyAndVisible];
6 }

UIWindow的方向
让我们看下面一个简单的例子,

1 -(void)viewWillLayoutSubviews
2 {
3     UIWindow *window = [[UIApplication sharedApplication] keyWindow];   
4     if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){
5         NSLog(@"window of LandsCape:%@",NSStringFromCGRect(window.frame));
6     } else{
7         NSLog(@"window of Portrait:%@",NSStringFromCGRect(window.frame));
8     }
9 }

iOS7模拟器打印结果:
2015-01-15 17:52:52.120 UIWindowDemo[67037:613] window of Portrait:{{0, 0}, {320, 568}}
2015-01-15 17:54:08.702 UIWindowDemo[67037:613] window of LandsCape:{{0, 0}, {320, 568}}

iOS8模拟器中打印结果:
2015-01-15 17:58:01.223 UIWindowDemo[67131:2455317] window of Portrait:{{0, 0}, {320, 568}}
2015-01-15 17:58:24.281 UIWindowDemo[67131:2455317] window of LandsCape:{{0, 0}, {568, 320}}

分析:从中我们可以看出,在iOS7中,不管手机是横屏状态还是竖屏状态,UIWindow总是Portrait方向。而iOS8中,UIWindow的方向与设备方向保持一致。

KeyBoard Window

KeyBoard是一个window,在介绍keyBoard之前我们先看下面这个简单的例子:

 1 -(void)btnClicked:(UIButton *)button
 2 {
 3     NSArray *array = [[UIApplication sharedApplication] windows];
 4     NSLog(@"array two = %@",array);
 5 }
 6 
 7 -(void)viewDidLoad {
 8     [super viewDidLoad];
 9     NSArray *array = [[UIApplication sharedApplication] windows];
10     NSLog(@"arrayOne = %@",array);
11     UIButton *btnOne = [UIButton buttonWithType:UIButtonTypeRoundedRect];
12     btnOne.frame = CGRectMake(0, 0, 200, 200);
13     [btnOne setTitle:@"Clicked me" forState:UIControlStateNormal];
14     [btnOne addTarget:self action:@selector(btnClicked:) forControlEvents:UIControlEventTouchUpInside];
15     [self.view addSubview:btnOne]; 
16      UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 300, 300, 100)];
17     textField.placeholder = @"Please write here";
18     [self.view addSubview:textField];
19 }

注意:再点击Button事件之前,我们最好触摸下UITextField,从而触发键盘时间。
点击Button事件之前打印: 2015-01-16 09:45:38.827 UIWindowDemo[70940:2531924] arrayOne = ( "<UIWindow: 0x7fc882d32a60; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7fc882d332a0>; layer = <UIWindowLayer: 0x7fc882d305a0>>" )

点击Button事件之后打印: 2015-01-16 09:47:07.851 UIWindowDemo[70940:2531924] array two = ( "<UIWindow: 0x7fc882d32a60; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7fc882d332a0>; layer = <UIWindowLayer: 0x7fc882d305a0>>", "<UITextEffectsWindow: 0x7fc882c30d20; frame = (0 0; 375 667); opaque = NO; gestureRecognizers = <NSArray: 0x7fc882c3ef60>; layer = <UIWindowLayer: 0x7fc882c13a50>>" )

分析:我们从中可以看出,当点击了Button事件后,画了一个UITextField。同时[[UIApplication sharedApplication] windows]中新添加了一个UITextEffectsWindow,而这个UITextEffectsWindow就是KeyBoard Window。如我们前面所说,在iOS7系统以及之前的系统中,UIWindow的坐标系永远是portrait方向,而iOS8中,UIWindow的坐标系与手机方向保持一致。那么键盘也是一个UIWindow,是不是也满足这个条件呢?下面我们观察下键盘的打印结果:

iOS7中,
Portrait方向:
2015-01-16 10:00:33.189 UIWindowDemo[71088:613] UITextEffectsWindow:<UITextEffectsWindow: 0x7f9631460fa0; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x7f96314618a0>; layer = <UIWindowLayer: 0x7f9631437600>>

Landscape方向:
2015-01-16 10:01:02.592 UIWindowDemo[71088:613] UITextEffectsWindow:<UITextEffectsWindow: 0x7f9631460fa0; frame = (0 0; 320 568); transform = [0, -1, 1, 0, -124, 124]; opaque = NO; gestureRecognizers = <NSArray: 0x7f96314618a0>; layer = <UIWindowLayer: 0x7f9631437600>>

iOS8中,
Portrait方向:
UITextEffectsWindow:<UITextEffectsWindow: 0x7fe621f49410; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x7fe621f1f490>; layer = <UIWindowLayer: 0x7fe621f1bbe0>>

Landscape方向: 2015-01-16 10:07:49.309 UIWindowDemo[71130:2542897] UITextEffectsWindow:<UITextEffectsWindow: 0x7fe621f49410; frame = (0 0; 568 320); opaque = NO; gestureRecognizers = <NSArray: 0x7fe621f1f490>; layer = <UIWindowLayer: 0x7fe621f1bbe0>>

从上面的打印结果我们可以看出,在iOS7中,keyBorad Window的方向也永远是Portrait的,当KeyBoard旋转的时候,系统会给KeyBoard一个transform的旋转变换。

Status Bar

Status Bar也是一个window,但是windows数组本身是不包含statusbar window。statusbar window是UIStatusBarWindow类型,我们可以通过下面这个方式来获取这个window

1 - (UIWindow *)statusWindow
2 {
3     NSString *statusBarString = [NSString stringWithFormat:@"_statusBarWindow"];
4     return [[UIApplication sharedApplication] valueForKey:statusBarString];
5 }

跟KeyBoard window类似,在iOS7中,statusbar frame同样不会改变。当你旋转设备的时候,系统会对statusbar进行transform旋转变换。但是注意,在iOS8 LandScape的情况下,status bar是被隐藏的.

1 CGRect rect = [UIApplication sharedApplication].statusBarFrame;  
2 NSLog(@"statusBarFrame %@", NSStringFromCGRect(rect));

我们可以看下面这个iOS8 Landscape的打印结果: 2015-01-16 11:29:19.235 UIWindowDemo[71511:2578866] statusFrame={{0, 320}, {0, 0}}

在iOS8 Landscape的情况下,Landscape的长和宽都为零,故默认是不显示出来的


Previous     Next