UIWindow知识归纳

2017-02-20  本文已影响237人  小蘑菇2

UIView的功能

负责渲染区域的内容,并且响应该区域内发生的触摸事件

UIWindow

在iOS App中,UIWindow是最顶层的界面内容,我们使用UIWindow和UIView来呈现界面。UIWindow并不包含任何默认的内容,但是它被当作UIView的容器,用于放置应用中所有的UIView。

从继承关系来看,UIWindow继承自UIView,所以UIWindow除了具有UIView的所有功能之外,还增加了一些特有的属性和方法,而我们最常用的方法,就是在App刚启动时,调用UIWindow的rootViewController(必须指定根控制器) 和 makeKeyAndVisible方法

状态栏和键盘都是特殊的UIWindow。

UIWindow在程序中主要起到三个作用:

1、作为容器,包含app所要显示的所有视图

2、传递触摸消息到程序中view和其他对象

3、与UIViewController协同工作,方便完成设备方向旋转的支持

通常我们可以采取两种方法将view添加到UIWindow中:

1、addSubview

直接将view通过addSubview方式添加到window中,程序负责维护view的生命周期以及刷新,但是并不会为去理会view对应的ViewController,因此采用这种方法将view添加到window以后,我们还要保持view对应的ViewController的有效性,不能过早释放。

2、rootViewController

rootViewController时UIWindow的一个遍历方法,通过设置该属性为要添加view对应的ViewController,UIWindow将会自动将其view添加到当前window中,同时负责ViewController和view的生命周期的维护,防止其过早释放

两个方法的区别:

以后的开发中,建议使用(2).因为方法(1)存在一些问题,比如说控制器上面可能由按钮,需要监听按钮的点击事件,如果是1,那么按钮的事件应该由控制器来进行管理。但控制器是一个局部变量,控制器此时已经不存在了,但是控制器的view还在,此时有可能会报错。注意:方法执行完,这个控制器就已经不存在了。

问题描述1:当view发生一些事件的时候,通知控制器,但是控制器已经销毁了,所以可能出现未知的错误。

问题描述2:添加一个开关按钮,让屏幕360度旋转(两者的效果不一样)。当发生屏幕旋转事件的时候,UIapplication对象会将旋转事件传递给uiwindow,uiwindow又会将旋转事件传递给它的根控制器,由根控制器决定是否需要旋转

UIapplication->uiwindow->根控制器(第一种方式没有根控制器,所以不能跟着旋转)。

提示:不通过控制器的view也可以做开发,但是在实际开发中,不要这么做,不要直接把view添加到UIWindow上面去。因为,难以管理。

WindowLevel

UIWindow的层级由一个UIWindowLevel类型属性windowLevel,该属性指示了UIWindow的层级,windowLevel有三种可取值。

并且层级是可以做加减的self.window.windowLevel = UIWindowLevelAlert+1;

UIKIT_EXTERN const UIWindowLevel UIWindowLevelNormal; //默认,值为0

UIKIT_EXTERN const UIWindowLevel UIWindowLevelAlert; //值为2000

UIKIT_EXTERN const UIWindowLevel UIWindowLevelStatusBar ; // 值为1000

Normal ,StatusBar,Alert.输出他们三个层级的值,我们发现从左到右依次是0,1000,2000,也就是说Normal级别是最低的,StatusBar处于中级,Alert级别最高。而通常我们的程序的界面都是处于Normal这个级别的,系统顶部的状态栏应该是处于StatusBar级别,提醒用户等操作位于Alert级别。根据window显示级别优先原则,级别高的会显示在最上层,级别低的在下面,我们程序正常显示的view在最底层;

如何获取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

四大对象的关系图

keyWindow

 当前app可以打开的多个window 如系统状态栏其实就是一个window ,程序启动的时候创建的默认的window ,弹出键盘也是一个window ,alterView 弹框也是window 。但是keyWindow只有一个 ,一般情况下就是我们程序启动时设置的默认的window

官方文档中是这样解释的 “The key window is the one that is designated to receive keyboard and other non-touch related events. Only one window at a time may be the key window." 翻译过来就是说,keyWindow是指定的用来接收键盘以及非触摸类的消息,而且程序中每一个时刻只能有一个window是keyWindow。

问题一:一个应用程序只能有一个主窗口,如果程序中创建了两个Window,那么谁是主窗口?

 ①iOS 7 以后,主窗口和次窗口是没有区别的

②iOS 7 之前,如果后面的窗口设置为主窗口,会把之前设置的主窗口覆盖掉 

问题二:只有主窗口才能响应键盘的输入事件?

在ios9.3的模拟器中,主窗口和非主窗口中的输入框都能输入文字,但是在ios6.1的模拟器中,非主窗口的输入框不能输入文字。  获取keyWindow的方式

UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;

UIViewController *rootViewController = keyWindow.rootViewController; 

注意:keyWindow不是一成不变的,当你创建alertView或者ActionSheet的时候,它们所在的window会变成keyWindow。也就是说系统默认创建的window首先变成keywindow,而当弹框的时候,alertView所在的window变成keywindow,默认的keywindow变成非keywindow。

 @property(nonatomic,readonly) NSArray  *windows;在windows数组里面,window是根据windowLevel来排列的,最后一个覆盖在最上面。这里的windows数组不包括系统提供的window,比如说状态栏就是在一个系统创建的window里面。

 测试代码如下:

#import "AppDelegate.h"

@interface AppDelegate (

)@property(strong, nonatomic) UIWindow *normalWindow;

@property(strong, nonatomic) UIWindow *coverStatusBarWindow;

@property(strong, nonatomic) UIWindow *alertLevelWindow;

@end

@implementation AppDelegate

- (void)coverWindowOnClicked{

    NSLog(@"tap tap 11111");   

 [[NSNotificationCenter defaultCenter]postNotificationName:@"kOnClickedStatusBarNotification" object:self userInfo:nil];}

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event{

NSLog(@"touchesBegan touchesBegan55555555555");

}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//1.

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

self.window.backgroundColor = [UIColor yellowColor];

self.window.rootViewController = [[UIViewController alloc]init];

[self.window makeKeyAndVisible];

NSLog(@"1hahah%f",[UIApplication sharedApplication].keyWindow.windowLevel);

//2.

UIWindow *normalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

normalWindow.backgroundColor = [UIColor grayColor];

normalWindow.windowLevel = UIWindowLevelNormal;

normalWindow.rootViewController = [[UIViewController alloc]init];

[normalWindow makeKeyAndVisible];

self.normalWindow = normalWindow;

UITextField *tf = [[UITextField alloc] init];

tf.frame = CGRectMake(10, 64, 100, 20);

tf.borderStyle = UITextBorderStyleRoundedRect;

[self.normalWindow addSubview:tf];

UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(coverWindowOnClicked)];

[self.normalWindow addGestureRecognizer:tap1];

NSLog(@"2hahah%f",[UIApplication sharedApplication].keyWindow.windowLevel);

//2. 创建覆盖着状态栏的window

UIWindow * coverStatusBarWindow =[[UIWindow alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 20)];

coverStatusBarWindow.rootViewController = [[UIViewController alloc]init];

coverStatusBarWindow.backgroundColor = [UIColor redColor];

//级别要比 状态栏的级别高

coverStatusBarWindow.windowLevel = UIWindowLevelStatusBar+1;

[coverStatusBarWindow makeKeyAndVisible];

self.coverStatusBarWindow = coverStatusBarWindow;

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(coverWindowOnClicked)];

[self.coverStatusBarWindow addGestureRecognizer:tap];

//想移除coverStatusBarWindow 将其赋值为空

//    self.coverStatusBarWindow = nil;

// 3.创建UIwindow1

self.alertLevelWindow = [[UIWindow alloc] initWithFrame:CGRectMake(50, 150, 200, 250)];

self.alertLevelWindow.backgroundColor = [UIColor blueColor];

UIViewController *vc1 = [[UIViewController alloc] init];

self.alertLevelWindow.rootViewController = vc1;

self.alertLevelWindow.windowLevel = UIWindowLevelAlert;

[self.alertLevelWindow makeKeyAndVisible];

// 给UIwindow1添加一个输入框

UITextField *tf1 = [[UITextField alloc] init];

tf1.frame = CGRectMake(10, 64, 100, 20);

tf1.borderStyle = UITextBorderStyleRoundedRect;

[self.alertLevelWindow addSubview:tf1];

UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(coverWindowOnClicked)];

[self.alertLevelWindow addGestureRecognizer:tap2];

NSLog(@"1hahah%f",[UIApplication sharedApplication].keyWindow.windowLevel);

NSLog(@"windows 刚启动 ---%@",[UIApplication sharedApplication].windows);

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyBoardShow:) name:UIKeyboardDidShowNotification object:nil];

return YES;

}

- (void)keyBoardShow:(NSNotification *)notif{

NSLog(@"windows 键盘弹出 ---%@",[UIApplication sharedApplication].windows);

NSLog(@"2hahah%f",[UIApplication sharedApplication].keyWindow.windowLevel);

}

可以得出以下结论: (实践是检验真理的唯一标准 网上有很多是错误的还是自己实践最好)

1) 同一层级的 最后一个显示出来,上一个被覆盖

2)UIWindow在显示的时候是不管KeyWindow是谁,都是Level优先的,即Level最高的始终显示在最前面。

3)谁最后设置的 makeKeyAndVisible 谁就是keyWindow 其他的也会显示出来 所有的window都可以监听键盘 和点击的事件

上一篇下一篇

猜你喜欢

热点阅读