UIWindow的一些总结

UIWindow 的学习

日常开发中,我们经常写这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.backgroundColor = UIColor.white
window?.makeKeyAndVisible()
if #available(iOS 9.0, *) {
window?.rootViewController = UIViewController()
}
// todo ...
let vc = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController()
window?.rootViewController = vc
return true
}

UIWindow的概念

UIWindow 是应用程序显示的背景,以及将接受的事件传递到视图的对象。

当我们打iPhone上的应用程序切换器,就会看到当前正在运行的应用程序的窗口。

  • 大多数应用程序仅需要提供一个主窗口,即可在屏幕上显示应用内容,也可以根据需要创建其它窗口显示其它内容。

  • 默认情况下,Xcode会提供应用程序的主窗口,即 Storyboards 会自动给 AppDelegate 的 window 属性提供值;如果不使用 Storyboards 则需要我们自己创建 window。

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

UIWindow 的一些属性方法

对 keyWindow 的操作

1
2
3
4
5
6
7
8
9
10
11
12
// 是否为 keyWindow
open var isKeyWindow: Bool { get }

// 系统自动调用该方法,子类可以重写该方法来执行与成为主窗口相关的任务
open func becomeKey()
// 系统自动调用以通知窗口它不再是键窗口
open func resignKey()

// 使对象成为主窗口,不更改window是否可见
open func makeKey()
// 显示窗口,并使其成为keyWindow
open func makeKeyAndVisible()

创建 window 时,它的 hidden 值默认为 YES,因此不会显示。通过调用makeKeyAndVisible可以让 window 显示出来,或者直接设置 window?.isHidden = false 。

keywindow 用来接收键盘输入以及非触摸类的消息事件,程序中每个时刻只能有一个 UIWindow 是 keyWindow。如果某个 UIWindow 内部的文本框不能输入文字,可能是因为这个 UIWindow 不是 keyWindow。

在进行 keyWindow 操作时,系统会发送如下通知:

1
2
3
4
UIWindow.didBecomeVisibleNotification
UIWindow.didBecomeHiddenNotification
UIWindow.didBecomeKeyNotification
UIWindow.didResignKeyNotification

rootViewController

设置了 window 的 rootViewController 后,会自动的把 View 添加到 window 中,并且负责管理 rootViewController 的生命周期。VC 会跟随 Window 的大小更改而更改

windowLevel 窗口在z轴上的位置

1
var windowLevel: UIWindow.Level

windowLevel 的值由 CGFloat 初始化获得,决定窗口在Z轴上显示的位置,默认值为 UIWindow.Level.normal(值为0),值越大越靠前显示

1
2
3
UIWindow.Level.normal.   ==> 0.0
UIWindow.Level.alert ==> 2000.0
UIWindow.Level.statusBar ==> 1000.0

将指定事件分发给View

1
func sendEvent(_ event: UIEvent)

UIApplication 调用该方法给 window 分发事件,window 再将事件分发到合适的目标,比如:可以调用此方法将自定义事件分派到窗口的事件响应程序链。

将坐标值与窗口的坐标系相互转换

1
2
3
4
5
6
7
8
// 把该window中的一个坐标转换成在目标window中的坐标值
open func convert(_ point: CGPoint, to window: UIWindow?) -> CGPoint
// 把目标window中的一个坐标转换成在该window中的坐标值
open func convert(_ point: CGPoint, from window: UIWindow?) -> CGPoint
// 把该window 中的一个frame转换成在目标window中的frame
open func convert(_ rect: CGRect, to window: UIWindow?) -> CGRect
// 把目标window中的一个frame转换成在该window中的frame
open func convert(_ rect: CGRect, from window: UIWindow?) -> CGRect

UIWindow 的一些操作

iOS中一些特殊的 window

1、UITextEffectsWindow,键盘所在的 window,iOS 8中新增的,其 windowLevel = 10;

2、UIRemoteKeyboardWindow,显示键盘按钮,iOS 9中新增的;

3、手机状态栏的UIStatusBarWindow, 属于系统级别, 不被App所持有;

4、UIAlertView 显示 _UIAlertControllerShimPresenterWindow;

获取应用程序的window

方式一:通过UIView
有时候window为null,原因是view没有完全加载完成或者在ViewDidload中才刚刚加载完,view的window属性无法被获取

1
self.view.window

方式二:通过UIApplication

1
2
3
4
5
// 获取keyWindow,但不一定是显示在最前面的
let window = UIApplication.shared.keyWindow

// 获取顶层window
let window2 = UIApplication.shared.windows.last

iOS 13以后的UIWindow

1、创建一个新的 window 显示 Alert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 该window是全局变量
var window = UIWindow(frame: UIScreen.main.bounds)
let windowScene = UIApplication.shared
.connectedScenes
.filter { $0.activationState == .foregroundActive }
.first
if let windowScene = windowScene as? UIWindowScene {
window = UIWindow(windowScene: windowScene)
}

window.windowLevel = UIWindow.Level.alert - 1
window.isHidden = false
window.backgroundColor = .clear
let vc = UIViewController.init()
vc.view.backgroundColor = UIColor.black.withAlphaComponent(0.2)
window.rootViewController = vc

2、iOS 13及以后,若使用了SceneDelegate, 则在iOS13上获取 keyWindow 会得到nil,正确操作如下:

1
2
3
4
5
6
7
8
9
10
UIApplication.shared.windows.first

或者

var window: UIWindow?
if #available(iOS 13.0, *) {
window = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window
} else {
window = UIApplication.shared.keyWindow
}

学习博客

卧龙小

􏲰􏱔􏱔􏲋􏲱􏲲􏲳􏲳􏲴􏲵􏰰􏰚􏲱􏲌􏲰􏰗􏰘􏲍􏰰􏰘􏱖􏱔􏲳􏰛􏰚􏱘􏲶􏲳􏲷􏱘􏰚􏲸􏲳􏲹􏲺􏲻􏰯􏲼􏲽看影成痴

关于ios 13使用makeKeyAndVisible无效的问题

iOS 13 Scene Delegate and multiple windows

文章作者: Czm
文章链接: http://yoursite.com/2020/06/19/UIWindow%E7%9A%84%E4%B8%80%E4%BA%9B%E6%80%BB%E7%BB%93/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Czm