Zev Eisenberg 的回答简单明了,但并不总是有效,并且可能会失败并显示以下警告消息:
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
这是因为 windows rootViewController 不在显示视图的顶部。为了纠正这个问题,我们需要遍历表示链,如我用 Swift 3 编写的 UIAlertController 扩展代码所示:
/// show the alert in a view controller if specified; otherwise show from window's root pree
func show(inViewController: UIViewController?) {
if let vc = inViewController {
vc.present(self, animated: true, completion: nil)
} else {
// find the root, then walk up the chain
var viewController = UIApplication.shared.keyWindow?.rootViewController
var presentedVC = viewController?.presentedViewController
while presentedVC != nil {
viewController = presentedVC
presentedVC = viewController?.presentedViewController
}
// now we present
viewController?.present(self, animated: true, completion: nil)
}
}
func show() {
show(inViewController: nil)
}
2017 年 9 月 15 日更新:
测试并确认,上述逻辑在新推出的 iOS 11 GM 种子中仍然有效。然而,agilityvision 投票最多的方法却没有:新创建的警报视图位于UIWindow
键盘下方,可能会阻止用户点击其按钮。这是因为在 iOS 11 中,所有高于键盘窗口的 windowLevels 都会降低到低于它的级别。
呈现的一个伪影是在呈现keyWindow
警报时键盘向下滑动的动画,并在解除警报时再次向上滑动。如果您希望键盘在演示期间停留在那里,您可以尝试从顶部窗口本身进行演示,如下面的代码所示:
func show(inViewController: UIViewController?) {
if let vc = inViewController {
vc.present(self, animated: true, completion: nil)
} else {
// get a "solid" window with the highest level
let alertWindow = UIApplication.shared.windows.filter { $0.tintColor != nil || $0.className() == "UIRemoteKeyboardWindow" }.sorted(by: { (w1, w2) -> Bool in
return w1.windowLevel < w2.windowLevel
}).last
// save the top window's tint color
let savedTintColor = alertWindow?.tintColor
alertWindow?.tintColor = UIApplication.shared.keyWindow?.tintColor
// walk up the presentation tree
var viewController = alertWindow?.rootViewController
while viewController?.presentedViewController != nil {
viewController = viewController?.presentedViewController
}
viewController?.present(self, animated: true, completion: nil)
// restore the top window's tint color
if let tintColor = savedTintColor {
alertWindow?.tintColor = tintColor
}
}
}
上述代码唯一不太重要的部分是它检查类名UIRemoteKeyboardWindow
以确保我们也可以包含它。尽管如此,上面的代码在 iOS 9、10 和 11 GM 种子中运行良好,具有正确的色调,并且没有键盘滑动伪影。