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种子上确实能很好地工作,具有正确的色泽并且没有键盘滑动伪影。