Display UIAlertController de la classe UIView/NSObject
j'ai working iOS application
Afin de support iOS8
, je remplace UIAlertView/UIActionSheet with
UIAlertController
.
problème:
Pour display UIAlertController j'ai besoin de presentViewController
méthode de la classe UIViewController.
mais UIAlertView est l'affichage des classes qui sont inherited
de l'
UIView or NSObject
,
Je ne peux pas obtenir la méthode [self presentViewController...]
pour une raison évidente.
Mon Travail:
J'ai essayé d'obtenir rootViewController de la fenêtre courante et display UIAlertController.
[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]
mais ont quelques problèmes de rotation comme si mon contrôleur de vue actuel n'avait pas de support de rotation il va tourner si UIAlertController est ouvert.
Question:
Est-ce que quelqu'un a fait face au même problème et a eu la solution sûre ?
dans l'affirmative, veuillez me fournir un exemple ou un guide
10 réponses
il semble que vous êtes actuellement (pré-iOS8) en train de déclencher une vue d'alerte à partir de votre objet view. C'est une très mauvaise pratique, car en général, les alertes doivent être déclenchées par des actions et de la logique. Et ce code devrait vivre dans les contrôleurs.
je vous suggère de reformuler votre code actuel pour déplacer la logique qui déclenche l'alerte vers le bon contrôleur, et ensuite vous pouvez facilement passer à iOS 8 en utilisant self
comme contrôleur.
si au lieu de cela, vous appelez l'alerte à partir d'un objet extérieur, puis passez dans le contrôleur à la méthode qui appelle l'alerte. Quelque part en amont, vous devez connaître le contrôleur.
j'ai résolu un problème essentiellement similaire aujourd'hui. Comme Jageen , j'ai rencontré une situation où je voulais présenter un Controller UIAlertController mais d'une classe non-UIViewController. Dans mon cas, je voulais qu'une alerte apparaisse lorsque le bloc de défaillance D'une requête HTTP est lancé.
C'est ce que j'ai utilisé et contrairement à notre ami ici, il a fonctionné tout à fait parfaitement pour moi.
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)
la meilleure solution pour les classes UIView
est inférieure à
ObjectiveC
UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController.........
- (UIViewController *)currentTopViewController
{
UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
while (topVC.presentedViewController)
{
topVC = topVC.presentedViewController;
}
return topVC;
}
Swift
var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
topVC = topVC!.presentedViewController
}
topVC?.presentViewController........
ma solution est ci-dessous:
Swift
class alert {
func msg(message: String, title: String = "")
{
let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil)
}
}
voici un exemple d'utilisation:
let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")
j'ai eu une situation où un subview contient un bouton pour le rejeter. Je vous présente une alerte pour confirmer l'action. Il envoie un message au délégué - qui est le contrôleur de vue contenant le subview - pour supprimer le subview
à l'origine, j'ai présenté UIAlertView à partir d'uivi. Refactoring pour UIAlertController, depuis le UIAlertController ne peut pas présenter lui-même comme un UIAlertView peut, je suis venu avec la suivante (dans l'Swift; facilement convertis en ObjC):
Ajouter un protocole au sous-vue:
protocol MySubviewDelegate {
// called when user taps subview/delete button
// or, you could call it from a gesture handler, etc.
func displayAlert(alert : UIAlertController)
// called when user confirms delete from the alert controller
func shouldRemoveSubview(sender : AnyObject)
}
Ajouter un délégué pour le subview, et Ajouter un gestionnaire pour le bouton / robinet gestuel:
class MySubview : UIView {
var subviewDelegate : MySubviewDelegate!
...
func handleTap(sender : AnyObject) {
// set up the alert controller here
var alert = UIAlertController(title: "Confirm Delete",
message: "This action is permanent. Do you wish to continue?",
preferredStyle: UIAlertControllerStyle.Alert)
// Cancel action
// nil handler means "no action if Cancel button selected"
alert.addAction(UIAlertAction(title: "Cancel",
style: UIAlertActionStyle.Cancel,
handler: nil))
// Confirm action
alert.addAction(UIAlertAction(title: "Confirm",
style: UIAlertActionStyle.Default,
handler: { (action : UIAlertAction!) -> Void in
// call delegate method to perform confirmed action, - i.e. remove
self.subviewDelegate.shouldRemoveSubview(self)
}))
// call delegate method to display alert controller
// send alert object to delegate
self.subviewDelegate.displayAlert(alert)
}
}
définit L'appelant UIViewController comme le délégué de subview, par exemple, dans sa méthode viewDidLoad (), et inclut les méthodes de protocole:
class viewController : UIViewController, MySubviewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
self.subviewDelegate = self
...
}
func displayAlert(alert : UIAlertController) {
presentViewController(alert, animated: true, completion: nil)
}
func shouldRemoveSubview(sender : AnyObject) {
// cast as UIView / MySubview subclass
var subview = sender as MySubview
// remove the subview / perform the desired action
subview.removeFromSuperview()
...
}
...
}
cela évite le besoin de trouver le contrôleur de vue le plus haut, ou passer des références aux contrôleurs de vue à les sous-vues (autre que dans un objet/délégué de la relation).
Dans Swift 3:
UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)
pour Swift 4 et plus
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
j'ai eu ce problème. Voir mon alors répondre ici pour le code pour obtenir le contrôleur de vue le plus haut avec lequel présenter un autre contrôleur de vue.
je suis d'accord que dans la plupart des cas, c'est une mauvaise pratique de présenter un contrôleur de vue à partir d'un objet qui n'est pas un contrôleur de vue, mais parfois vous en avez besoin.
Pour Afficher UIAlertController dans la Classe NSObject utilisez Code ci-dessous.
UIAlertController * popup = [UIAlertController
alertControllerWithTitle:nil
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* cancel = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action) {
[popup dismissViewControllerAnimated:YES completion:nil];
}];
[popup addAction:cancel];
UIViewController *rootViewController = [[Helper shareInstance] topViewController];
[rootViewController presentViewController:popup animated:YES completion:nil];
// Méthode ci-Dessous dans Votre Global de la Classe Helper.
- (UIViewController *)topViewController {
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)topViewController:(UIViewController *)rootViewController {
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
en général, les alertes doivent être traitées dans le contrôleur de vue. Voici un exemple du code requis:
Swift 3
private func displayError(message: String) {
let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
alertController.addAction(okayAction)
present(alertController, animated: true, completion: nil)
}