大多数人对于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的长和宽都为零,故默认是不显示出来的