La risposta di Zev Eisenberg è semplice e diretta, ma non sempre funziona e potrebbe non riuscire con questo messaggio di avviso:
Warning: Attempt to present <UIAlertController: 0x7fe6fd951e10>
on <ThisViewController: 0x7fe6fb409480> which is already presenting
<AnotherViewController: 0x7fe6fd109c00>
Questo perché rootViewController di Windows non si trova nella parte superiore delle viste presentate. Per correggere questo, dobbiamo camminare lungo la catena di presentazione, come mostrato nel mio codice di estensione UIAlertController scritto in 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)
}
Aggiornamenti il 15/09/2017:
Testato e confermato che la logica di cui sopra funziona ancora alla grande nel seme iOS 11 GM appena disponibile. Il metodo più votato da agilityvision, tuttavia, non lo fa: la vista di allerta presentata in una nuova coniataUIWindow
è sotto la tastiera e potenzialmente impedisce all'utente di toccare i suoi pulsanti. Questo perché in iOS 11 tutti i livelli delle finestre superiori a quelli della finestra della tastiera vengono abbassati a un livello inferiore.
Un artefatto della presentazione da keyWindow
sebbene è l'animazione della tastiera che scorre verso il basso quando viene presentato l'avviso e che si sposta di nuovo verso l'alto quando viene disattivato l'avviso. Se vuoi che la tastiera rimanga lì durante la presentazione, puoi provare a presentare dalla finestra superiore stessa, come mostrato nel codice seguente:
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
}
}
}
L'unica parte non eccezionale del codice sopra è che controlla il nome della classe UIRemoteKeyboardWindow
per assicurarsi che possiamo includerlo anche. Tuttavia, il codice sopra funziona alla perfezione con i semi GM di iOS 9, 10 e 11, con il giusto colore e senza gli artefatti scorrevoli della tastiera.