Window
每个iOS应用程序都至少需要一个window(UIWindow类的一个实例),有些可能包含多个window。window对象具有以下职责:
它包含您应用程序的可见内容。
它在将触摸事件传递到视图和其他应用程序对象中扮演着关键角色。
它与您的应用程序的视图控制器配合使用,可以方便地更改方向。
在iOS中,window没有标题栏,关闭框或任何其他视觉装饰。window始终只是一个或多个视图的空白容器。此外,应用程序不会通过显示新window来更改其内容。当您想要更改显示的内容时,可以更改window的最前面的视图。
大多数iOS应用程序在其生命周期内仅创建和使用一个window。该window跨越设备的整个主屏幕,并在应用程序生命周期的早期从应用程序的主nib文件加载(或通过程序创建)。但是,如果应用程序支持使用外部显示器进行视频输出,则它可以创建一个附加window以在该外部显示器上显示内容。所有其他window通常由系统创建,并且通常是响应于特定事件(例如来电)而创建的。
Windows涉及的任务
对于许多应用程序,应用程序与其window交互的唯一时间是在启动时创建window。但是,您可以使用应用程序的window对象执行一些与应用程序相关的任务:
使用window对象可将点和矩形与window的本地坐标系相互转换。例如,如果在window坐标中提供了一个值,则在尝试使用它之前可能需要将其转换为特定视图的坐标系。
使用window通知来跟踪与window相关的更改。Windows在显示或隐藏它们或接受或放弃键状态时会生成通知。您可以使用这些通知在应用程序的其他部分中执行操作。
创建和配置Window
您可以通过编程方式或使用Interface Builder创建和配置应用程序的主窗口。无论哪种情况,您都需要在启动时创建窗口,并应保留该窗口并将其引用存储在您的应用程序委托对象中。如果您的应用程序创建了其他窗口,请在需要时让应用程序延迟创建它们。例如,如果您的应用程序支持在外部显示器上显示内容,则它应等到显示器连接后再创建相应的窗口。
无论您的应用程序是在前台启动还是在后台启动,都应始终在启动时创建应用程序的主窗口。创建和配置窗口本身并不是一项昂贵的操作。但是,如果应用程序直接在后台启动,则应避免使窗口可见,直到应用程序进入前台为止。
在Interface Builder中创建Windows
使用Interface Builder创建应用程序的主窗口很简单,因为Xcode项目模板可以帮您完成。每个新的Xcode应用程序项目都包含一个主nib文件(通常使用MainWindow.xib或其他名称),其中包含该应用程序的主窗口。此外,这些模板还在应用程序委托对象中为该窗口定义了出口。您可以使用此出口来访问代码中的窗口对象。
在Interface Builder中创建窗口时,建议您在属性检查器中启用“启动时全屏”选项。如果未启用此选项,并且您的窗口小于目标设备的屏幕,则某些视图将不会收到触摸事件。这是因为窗口(如所有视图)不会在其边界矩形之外接收触摸事件。由于默认情况下视图不会被裁剪到窗口的边界,因此视图仍然显示可见,但事件不会到达它们。启用“启动时全屏”选项可确保为当前屏幕调整窗口大小。
如果要改造项目以使用Interface Builder,则使用Interface Builder创建窗口是将窗口对象拖动到nib文件中的简单问题。当然,您还应该执行以下操作:
要在运行时访问窗口,您应该将窗口连接到outlet,通常是在应用程序委托或nib文件的文件所有者中定义的。
如果您的改造计划包括将新的nib文件设为应用程序的主要nib文件,则还必须将应用程序的Info.plist文件中的NSMainNibFile密钥设置为nib文件的名称。更改此键的值可确保在调用应用程序委托的application:didFinishLaunchingWithOptions:方法时,已加载nib文件并可供使用。
以编程方式创建窗口
如果您希望通过编程方式创建应用程序的主窗口,则应在应用程序中包括与以下代码类似的代码:didFinishLaunchingWithOptions:应用程序委托的方法:
在前面的示例中,self.window被假定为配置为保留窗口对象的应用程序委托的声明属性。如果要为外部显示器创建窗口,则将其分配给其他变量,并且需要指定表示该显示器的非主UIScreen对象的边界。
创建窗口时,应始终将窗口的大小设置为屏幕的整个边界。您不应减小窗口的大小以容纳状态栏或任何其他项目。无论如何,状态栏始终漂浮在窗口顶部,因此您应该收缩以容纳状态栏的唯一一件事就是放入窗口的视图。并且,如果您使用的是视图控制器,则视图控制器应自动处理视图的大小。
向窗口添加内容
每个窗口通常都有一个根视图对象(由相应的视图控制器管理),该对象包含代表您的内容的所有其他视图。使用单个根视图简化了更改界面的过程。要显示新内容,您要做的就是替换根视图。要在窗口中安装视图,请使用addSubview:方法。例如,要安装由视图控制器管理的视图,您将使用类似于以下代码:
除了上述代码,您还可以在nib文件中配置窗口的rootViewController属性。该属性提供了一种使用nib文件而不是通过编程方式配置窗口根视图的便捷方法。如果从其nib文件加载窗口时设置了此属性,则UIKit会自动从关联的视图控制器安装视图作为窗口的根视图。此属性仅用于安装根视图,窗口不使用它与视图控制器进行通信。
您可以将任何所需的视图用作窗口的根视图。根据您的界面设计,根视图可以是充当一个或多个子视图的容器的通用UIView对象,根视图可以是标准系统视图,或者根视图可以是您定义的自定义视图。通常用作根视图的一些标准系统视图包括滚动视图,表视图和图像视图。
配置窗口的根视图时,您需要设置其初始大小和在窗口中的位置。对于不包含状态栏或显示半透明状态栏的应用程序,请设置视图大小以匹配窗口的大小。对于显示不透明状态栏的应用程序,将视图置于状态栏下方,并相应地减小其大小。从视图的高度减去状态栏的高度可防止遮挡视图的顶部。
如果窗口的根视图由容器视图控制器(例如选项卡栏控制器,导航控制器或拆分视图控制器)提供,则无需自己设置视图的初始大小。容器视图控制器会根据状态栏是否可见来自动调整其视图的大小。
更改窗口级别
每个UIWindow对象都有一个可配置的windowLevel属性,该属性确定该窗口相对于其他窗口的放置方式。在大多数情况下,您无需更改应用程序窗口的级别。在创建时,新窗口会自动分配给普通窗口级别。正常窗口级别指示该窗口显示与应用程序相关的内容。较高的窗口级别保留用于需要浮动在应用程序内容上方的信息,例如系统状态栏或警报消息。而且,尽管您可以自己将窗口分配给这些级别,但是当您使用特定的界面时,系统通常会为您执行此操作。例如,当您显示或隐藏状态栏或显示警报视图时,系统会自动创建所需的窗口以显示这些项目。
监视窗口更改
如果要跟踪应用程序内部窗口的出现或消失,可以使用以下与窗口相关的通知来进行跟踪:
UIWindowDidBecomeVisibleNotification
UIWindowDidBecomeHiddenNotification
UIWindowDidBecomeKeyNotification
UIWindowDidResignKeyNotification
这些通知是根据您应用程序窗口中的程序更改而传递的。因此,当您的应用程序显示或隐藏窗口时,将相应地传递UIWindowDidBecomeVisibleNotification和UIWindowDidBecomeHiddenNotification通知。当您的应用程序进入后台执行状态时,不会发送这些通知。即使您的应用程序在后台时窗口未显示在屏幕上,它仍被认为在您的应用程序上下文中可见。
UIWindowDidBecomeKeyNotification和UIWindowDidResignKeyNotification通知可帮助您的应用程序跟踪哪个窗口是关键窗口,也就是说,哪个窗口当前正在接收键盘事件和其他与触摸无关的事件。触摸事件传递到发生触摸的窗口,而没有关联坐标值的事件传递到应用程序的键窗口。一次仅一个窗口可能是关键。
在外接显示器上显示内容
要在外部显示器上显示内容,必须为应用程序创建一个附加窗口,并将其与代表外部显示器的屏幕对象相关联。默认情况下,新窗口通常与主屏幕关联。更改窗口的关联屏幕对象会导致该窗口的内容重新路由到相应的显示器。窗口与正确的屏幕相关联后,您可以向其添加视图并像在应用程序的主屏幕上一样显示它。
UIScreen类维护代表可用硬件显示的屏幕对象列表。通常,对于任何基于iOS的设备,只有一个屏幕对象代表主显示屏,但是支持连接到外部显示器的设备可以具有一个附加的屏幕对象。支持外部显示器的设备包括具有Retina显示器的iPhone和iPod touch设备以及iPad。较旧的设备(例如iPhone 3GS)不支持外部显示器。
因为外部显示器本质上是视频输出连接,所以不应期望与外部显示器相关联的窗口中的视图和控件发生触摸事件。此外,您的应用程序有责任根据需要更新窗口的内容。因此,要镜像主窗口的内容,您的应用程序将需要为外部显示器的窗口创建一组重复的视图,并与主窗口中的视图一起进行更新。
以下各节介绍了在外部显示器上显示内容的过程。但是,以下步骤总结了基本过程: 1. 在应用程序启动时,注册屏幕连接和断开连接通知。 2. 当需要在外部显示器上显示内容时,请创建并配置一个窗口。
使用UIScreen的screens属性获取外部显示的屏幕对象。
创建一个UIWindow对象,并根据屏幕(或您的内容)调整其大小。
将外部显示的UIScreen对象分配给窗口的screen属性。
根据需要调整屏幕对象的分辨率以支持您的内容。
将任何适当的视图添加到窗口。
显示窗口并正常更新。
处理屏幕连接和断开连接通知
屏幕连接和断开连接通知对于妥善处理外部显示器的更改至关重要。当用户连接或断开显示器连接时,系统会向您的应用程序发送适当的通知。您应该使用这些通知来更新应用程序状态并创建或释放与外部显示器关联的窗口。
关于连接和断开连接通知,要记住的重要一点是,即使您的应用程序在后台挂起,它们也可以随时出现。因此,最好观察在应用程序运行时持续存在的来自对象的通知,例如您的应用程序委托。如果您的应用程序已暂停,则通知将排队,直到您的应用程序退出暂停状态并开始在前台或后台运行。
如果将外部显示器连接到设备后您的应用程序处于活动状态,则应为该显示器创建第二个窗口,并在其中填充一些内容。内容不必是您要呈现的最终内容。例如,如果您的应用程序尚未准备好使用额外的屏幕,则可以使用第二个窗口显示一些占位符内容。如果您没有为屏幕创建窗口,或者创建但未显示窗口,则外部显示屏上会显示黑场。
为外部显示器配置窗口
要在外部屏幕上显示窗口,必须将其与正确的屏幕对象关联。此过程涉及找到合适的UIScreen对象,并将其分配给窗口的screen属性。您可以从UIScreen的screens类方法获取屏幕对象列表。此方法返回的数组始终包含至少一个代表主屏幕的对象。如果存在第二个对象,则该对象表示已连接的外部显示器。
在显示窗口之前,应始终将屏幕与窗口关联。尽管可以更改当前可见窗口的屏幕,但这是一项昂贵的操作,应避免。
一旦显示了外部屏幕的窗口,您的应用程序就可以像其他任何窗口一样开始对其进行更新。您可以根据需要添加和删除子视图,更改子视图的内容,为视图添加动画效果,并根据需要使它们的内容无效。
配置外接显示器的屏幕模式
根据您的内容,您可能需要在将窗口与其关联之前更改屏幕模式。许多屏幕支持多种分辨率,其中一些分辨率使用不同的像素长宽比。屏幕对象默认情况下使用最常见的屏幕模式,但是您可以将该模式更改为更适合您的内容的模式。例如,如果您要使用OpenGL ES来实现游戏,并且纹理是为640 x 480像素屏幕设计的,则可以更改具有更高默认分辨率的屏幕的屏幕模式。
如果计划使用默认模式以外的其他屏幕模式,则应在将屏幕与窗口关联之前,将该模式应用于UIScreen对象。UIScreenMode类定义单个屏幕模式的属性。您可以从屏幕的availableModes属性获取屏幕支持的模式的列表,并在列表中进行迭代以找到符合您需求的模式。您可以从屏幕的availableModes属性获取屏幕支持的模式的列表,并在列表中进行迭代以找到符合您需求的模式。
Last updated
Was this helpful?