深入了解iOS开发中UIWindow的相关使用

UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow。

iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了。

一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow。也就说,没有UIWindow,就看不见任何UI界面。

如何获取UIWindow

(1)[UIApplication sharedApplication].windows  在本应用中打开的UIWindow列表,这样就可以接触应用中的任何一个UIView对象(平时输入文字弹出的键盘,就处在一个新的UIWindow中);

(2)[UIApplication sharedApplication].keyWindow(获取应用程序的主窗口)用来接收键盘以及非触摸类的消息事件的UIWindow,而且程序中每个时刻只能有一个UIWindow是keyWindow;

注:经过代码验证,非keyWindow 也是可以接受键盘消息的;

提示:如果某个UIWindow内部的文本框不能输入文字,可能是因为这个UIWindow不是keyWindow;

(3)view.window获得某个UIView所在的UIWindow。

UIWindowLevel

我们知道UIWindow 有三个层级,分别是Normal ,StatusBar,Alert.输出他们三个层级的值,我们发现从左到右依次是0,1000,2000,也就是说Normal级别是最低的,StatusBar处于中级,Alert级别最高。而通常我们的程序的界面都是处于Normal这个级别的,系统顶部的状态栏应该是处于StatusBar级别,UIActionSheet和UIAlertView这些通常都是用来中断正常流程,提醒用户等操作,因此位于Alert级别。

根据window显示级别优先原则,级别高的会显示在最上层,级别低的在下面,我们程序正常显示的view在最底层;

keyWindow

官方文档中是这样解释的 “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。

观察UIWindow的文档,我们可以发现里面有四个关于window变化的通知:

  UIWindowDidBecomeVisibleNotification

  UIWindowDidBecomeHiddenNotification

  UIWindowDidBecomeKeyNotification

  UIWindowDidResignKeyNotification

  这四个通知对象中的object都代表当前已显示(隐藏),已变成keyWindow(非keyWindow)的window对象,其中的userInfo则是空的。于是我们可以注册这个四个消息,再打印信息来观察keyWindow的变化以及window的显示,隐藏的变动

变成keywindow 的流程是这样的

1.程序默认的window先显示出来

2.默认的window再变成keywindow

3.AlertView 的window显示出来

4.默认的window变成keywindow

5.最终AlertView的window变成keywindow

iOS8开始UIWindow的bounds发生变化(Window本身发生了旋转)
 
  iOS 7之前Window的bounds不会随着方向而变化,但是到了iOS 8以后,随着设备方向的旋转,window.bounds.size.width和window.bounds.size.height也会相应发生变化。
 
  做个很简单的测试,代码如下:

代码如下:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
   
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(orientationChanged:)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];
   
    return YES;
}

- (void)orientationChanged:(NSNotification*)noti {
   
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    NSString *orientationDes = nil;
    switch (orientation) {
        case UIDeviceOrientationLandscapeLeft:
            orientationDes = @"UIInterfaceOrientationLandscapeRight";
            break;
        case UIDeviceOrientationLandscapeRight:
            orientationDes = @"UIInterfaceOrientationLandscapeLeft";
            break;
        case UIDeviceOrientationPortrait:
            orientationDes = @"UIInterfaceOrientationPortrait";
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            orientationDes = @"UIInterfaceOrientationPortraitUpsideDown";
            break;
        default:
            orientationDes = @"";
            break;
    }
   
    NSLog(@"system ver: %@, \rorientaion: %@, \rwindow bounds: %@",
          [UIDevice currentDevice].systemVersion,
          orientationDes,
          NSStringFromCGRect(self.window.bounds));
}

  示例代码很简单,新建一个工程,然后在delegate中直接添加以上代码即可。
 
  iOS 8上运行结果为:

代码如下:

2014-06-04 09:26:32.016 SviOS8[4143:61114] system ver: 8.0,

orientaion: UIInterfaceOrientationLandscapeRight,

window bounds: {{0, 0}, {320, 480}}

2014-06-04 09:26:34.788 SviOS8[4143:61114] system ver: 8.0,

orientaion: UIInterfaceOrientationPortrait,

window bounds: {{0, 0}, {480, 320}}

2014-06-04 09:26:35.791 SviOS8[4143:61114] system ver: 8.0,

orientaion: UIInterfaceOrientationLandscapeLeft,

window bounds: {{0, 0}, {320, 480}}

2014-06-04 09:26:47.468 SviOS8[4143:61114] system ver: 8.0,

orientaion: UIInterfaceOrientationPortraitUpsideDown,

window bounds: {{0, 0}, {480, 320}}

  iOS 7及之前的版本运行结果为:

代码如下:

2014-06-04 09:39:00.527 SviOS8[4380:70b] system ver: 7.0.3,

orientaion: UIInterfaceOrientationLandscapeRight,

window bounds: {{0, 0}, {320, 480}}

2014-06-04 09:39:00.895 SviOS8[4380:70b] system ver: 7.0.3,

orientaion: UIInterfaceOrientationPortrait,

window bounds: {{0, 0}, {320, 480}}

2014-06-04 09:39:01.225 SviOS8[4380:70b] system ver: 7.0.3,

orientaion: UIInterfaceOrientationLandscapeLeft,

window bounds: {{0, 0}, {320, 480}}

2014-06-04 09:39:11.004 SviOS8[4380:70b] system ver: 7.0.3,

orientaion: UIInterfaceOrientationPortraitUpsideDown,

window bounds: {{0, 0}, {320, 480}}

  通过对比我们可以清晰的看到iOS 8中UIWindow在处理旋转时策略的变更,虽然会因为与之前的版本不同导致现有项目布局存在的bug,但是可以看到iOS 8中的处理方式更加符合我们的预期,在竖向的时候我们就获取到width < height, 在横向则是 width > height,这个符合所见即所得的原则。
 
  题外话,不管是iOS 7还是之前的版本,以及最新出的iOS 8,所有的ViewController的bounds都是正确的,所以只需要坚持一个原则“所有布局都是基于VC.view.bounds布局,那么你的App的显示就一切正常。”

(0)

相关推荐

  • iOS应用开发中视图控件UIWindow的基本使用教程

    一.简单介绍 iPhone应用程序通常只有一个窗口,表示为一个UIWindow类的实例.应用程序在启动时(或者从nib文件进行装载)创建这个窗口,并往窗口中加入一或多个视图并显示出来.之后我们很少需要再次引用它.UIWindow对象是所有UIView的根,管理和协调的应用程序的显示.一般应用程序只有一个UIWindow对象,即使有多个UIWindow对象,也只有一个UIWindow可以接受到用户的触屏事件. 在IOS中,UIWindow对象并没有像windows应用程序中常见的关闭框或标题栏这样

  • 详解iOS设计中的UIWindow使用

    每一个IOS程序都有一个UIWindow,在我们通过模板简历工程的时候,xcode会自动帮我们生成一个window,然后让它变成keyWindow并显示出来.这一切都来的那么自然,以至于我们大部分时候都忽略了自己也是可以创建UIWindow对象.   通常在我们需要自定义UIAlertView的时候(IOS 5.0以前AlertView的背景样式等都不能换)我们可以使用UIWindow来实现(设置windowLevel为Alert级别),网上有很多例子,这里就不详细说了. 一.UIWindowL

  • 深入了解iOS开发中UIWindow的相关使用

    UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow. iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了. 一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow.也就说,没有UIWindow,就看不见任何UI界面. 如何获取UIWindow (1)[UIApplication sharedApplication].windo

  • 详解iOS开发中Keychain的相关使用

    一.Keychain 基础 根据苹果的介绍,iOS设备中的Keychain是一个安全的存储容器,可以用来为不同应用保存敏感信息比如用户名,密码,网络密码,认证令牌.苹果自己用keychain来保存Wi-Fi网络密码,VPN凭证等等.它是一个sqlite数据库,位于/private/var/Keychains/keychain-2.db,其保存的所有数据都是加密过的. 开发者通常会希望能够利用操作系统提供的功能来保存凭证(credentials)而不是把它们(凭证)保存到NSUserDefault

  • iOS开发中使用UIScrollView实现无限循环的图片浏览器

    一.概述 UIKit框架中有大量的控件供开发者使用,在iOS开发中不仅可以直接使用这些控件还可以在这些控件的基础上进行扩展打造自己的控件.在这个系列中如果每个控件都介绍一遍确实没有必要,所谓授人以鱼不如授人以渔,这里会尽可能让大家明白其中的原理,找一些典型的控件进行说明,这样一来大家就可以触类旁通.今天我们主要来看一下UIScrollView的内容: UIView UIScrollView 实战--图片浏览器 二.UIView 在熟悉UIScrollView之前很有必要说一下UIView的内容.

  • iOS开发中Quartz2D控制圆形缩放和实现刷帧效果

    Quartz2D简要回顾 一.什么是Quartz2D Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF 截图\裁剪图片 自定义UI控件 二.Quartz2D在iOS开发中的价值 为了便于搭建美观的UI界面,iOS提供了UIKit框架,⾥⾯有各种各样的UI控件 UILabel:显⽰文字 UIImageView:显示图片 UIButton:同时显示图片和⽂

  • 比较IOS开发中常用视图的四种切换方式

    在iOS开发中,比较常用的切换视图的方式主要有以下几种: 1. push.pop 使用举例(ViewController假设为需要跳转的控制器): [self.navigationController pushViewController:ViewController animated:YES]; //入栈,跳转到指定控制器视图 [self.navigationController popViewControllerAnimated:YES]; //弹栈,返回到前一个视图 [self.navig

  • iOS开发中常用的各种动画、页面切面效果

    今天主要用到的动画类是CALayer下的CATransition至于各种动画类中如何继承的在这也不做赘述,网上的资料是一抓一大把.好废话少说切入今天的正题. 一.封装动画方法 1.用CATransition实现动画的封装方法如下,每句代码是何意思,请看注释之. #pragma CATransition动画实现 - (void) transitionWithType:(NSString *) type WithSubtype:(NSString *) subtype ForView : (UIVi

  • iOS开发中UIWebView的加载本地数据的三种方式

    UIWebView是IOS内置的浏览器,可以浏览网页,打开文档 html/htm pdf docx txt等格式的文件. safari浏览器就是通过UIWebView做的. 服务器将MIME的标识符等放入传送的数据中告诉浏览器使用那种插件读取相关文件. uiwebview加载各种本地文件(通过loadData方法): UIWebView加载内容的三种方式: 1 加载本地数据文件 指定文件的MIMEType 编码格式使用@"UTF-8" 2加载html字符串(可以加载全部或者部分html

  • iOS开发中class和#import的区别介绍

    在iOS开发过程中,我们在一些源码中经常会看到导包的时候有的用#import进行导包,但是有的的时候也会看到用@class进行导包,那么这两种方式有什么区别呢? 一 @class和#import的主要区别 首先说一下最主要的区别: •使用#import引入一个类的头文件,编译时会将该类的头文件中的所有信息都引入,包含属性和方法: •使用@class仅仅是告诉编译器这是一个类,并不会因入该类的其他信息,而我们所关心的也仅此一点,而不需要知道该类的内部有哪些属性和方法,因此使用@class可以提升编

  • iOS开发中runtime常用的几种方法示例总结

    前言 Objective-C runtime是一个实现Objective-C语言的C库.它是一门编译型语言.也是一门动态型的语言(这里强调下OC是静态类型语言),之前没接触runtime的时候也不觉着它有多重要,接触之后才发现其实runtime挺强大的.就拿我们在iOS开发中所使用的OC编程语言来讲,OC之所以能够做到即是编译型语言,又能做到动态语言,就是得益于runtime的机制. 最近公司项目中用了一些 runtime 相关的知识, 初看时有些蒙, 虽然用的并不多, 但还是想着系统的把 ru

  • IOS开发中加载大量网络图片优化方法

    IOS开发中加载大量网络图片如何优化 1.概述 在IOS下通过URL读一张网络图片并不像其他编程语言那样可以直接把图片路径放到图片路径的位置就ok,而是需要我们通过一段类似流的方式去加载网络图片,接着才能把图片放入图片路径显示.比如: -(UIImage *) getImageFromURL:(NSString *)fileURL { //NSLog(@"执行图片下载函数"); UIImage * result; NSData * data = [NSData dataWithCont

随机推荐