Jawaban Zev Eisenberg sederhana dan langsung, tetapi tidak selalu berhasil, dan mungkin gagal dengan pesan peringatan ini:
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
Ini karena windows rootViewController tidak di bagian atas tampilan yang disajikan. Untuk memperbaikinya kita perlu menjalankan rantai presentasi, seperti yang ditunjukkan dalam kode ekstensi UIAlertController saya yang ditulis dalam Swift 3:
/// 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)
}
Pembaruan pada 15/15/2017:
Diuji dan dikonfirmasi bahwa logika di atas masih berfungsi dengan baik di seed iOS 11 GM yang baru tersedia. Metode pemilihan teratas oleh agilityvision, bagaimanapun, tidak: tampilan peringatan disajikan dalam yang baru dicetakUIWindow
berada di bawah keyboard dan berpotensi mencegah pengguna mengetuk tombolnya. Ini karena di iOS 11 semua windowLevel lebih tinggi dari jendela keyboard diturunkan ke level di bawahnya.
Salah satu artefak presentasi dari keyWindow
adalah animasi keyboard geser ke bawah ketika peringatan disajikan, dan geser ke atas saat peringatan diberhentikan. Jika Anda ingin keyboard tetap berada di sana selama presentasi, Anda dapat mencoba menyajikan dari jendela atas itu sendiri, seperti yang ditunjukkan pada kode di bawah ini:
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
}
}
}
Satu-satunya bagian yang tidak begitu bagus dari kode di atas adalah bahwa ia memeriksa nama kelas UIRemoteKeyboardWindow
untuk memastikan kita juga bisa memasukkannya. Namun demikian kode di atas tidak berfungsi dengan baik di iOS 9, 10 dan 11 benih GM, dengan warna warna yang tepat dan tanpa artefak sliding keyboard.