【问题标题】:Show UIAlertController if already showing an Alert如果已经显示警报,则显示 UIAlertController
【发布时间】:2014-10-17 06:53:30
【问题描述】:

旧版UIAlertView 和新版UIAlertController 的区别在于后者需要使用presentViewController:animated:completion: 呈现到特定的视图控制器上。这给我的用例带来了一个尴尬的问题:如果出现第二个视图控制器(例如由于网络连接失败而导致的错误对话框)时已经显示了UIAlertController(例如评级对话框)怎么办。我经历过,在这种情况下,第二个 UIAlertController 只是没有显示。

编辑:目前我尝试显示警报,我不知道当前是否有任何显示。

你如何应对这种情况?

【问题讨论】:

标签: ios8 uialertcontroller


【解决方案1】:

我找到了一种解决方法来找出我可以在哪个视图控制器上显示警报。我也贴出答案here

@implementation UIViewController (visibleViewController)

- (UIViewController *)my_visibleViewController {

    if ([self isKindOfClass:[UINavigationController class]]) {
        // do not use method visibleViewController as the presentedViewController could beingDismissed
        return [[(UINavigationController *)self topViewController] my_visibleViewController];
    }

    if ([self isKindOfClass:[UITabBarController class]]) {
        return [[(UITabBarController *)self selectedViewController] my_visibleViewController];
    }

    if (self.presentedViewController == nil || self.presentedViewController.isBeingDismissed) {
        return self;
    }

    return [self.presentedViewController my_visibleViewController];
}

@end

// To show a UIAlertController, present on the following viewcontroller:
UIViewController *visibleViewController = [[UIApplication sharedApplication].delegate.window.rootViewController my_visibleViewController];

【讨论】:

    【解决方案2】:

    由于UIAlertController 本身就是UIViewController,因此您可以在第一个UIAlertController 的基础上通过现有的呈现来呈现第二个UIAlertController

    alertController.PresentViewController(alertController2,  animated: true, completionHandler: null)
    

    【讨论】:

    • 问题是必须先找出最上面的viewcontroller。假设我不知道是否显示了 amy 警报或其他显示的视图控制器。
    • 使用这个来获取顶级ViewController: private UIViewController GetTopPresentedViewController() { UIViewController currentVC = this.viewController; while (true) { UIViewController nextVC = currentVC.PresentedViewController; if (nextVC == null) { return currentVC; } currentVC = nextVC; } }
    • 查看我的答案 - 不要忘记 isBeingDismissed 标志。
    【解决方案3】:

    当应用程序必须在窗口上显示一些警报时,此代码满足要求,并且在显示之前检查是否已经显示了任何其他 AlertController,如果已显示,则在出现的 Alertcontroller 上显示警报,否则在窗口上显示。

    这里还有另一种选择,您可以根据需要对其进行优化。

         func showAlert(message:String) {
    
            if let alert = self.checkIfAlertViewHasPresented() {
                alert.presentViewController(alertController, animated: true, completion: nil)
    
            } else {
                self.window?.rootViewController!.presentViewController(alertController, animated: true, completion: nil)
            }
        }
    
        func checkIfAlertViewHasPresented() -> UIAlertController? {
    
            if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
                while let presentedViewController = topController.presentedViewController {
                    topController = presentedViewController
                }
                if topController is UIAlertController {
                   return (topController as! UIAlertController)
                } else {
                   return nil
                }
            }
            return nil
        }
    

    【讨论】:

    • 这不包括接受的答案中涵盖的一些特殊情况。
    • @fabb 同意你的看法。我在编写代码之前已经说明了该代码块满足的条件。如果一些新手开发人员在理解其他复杂情况时遇到问题,我认为我的答案是次要选择。
    • 恕我直言,尤其是新手应该被教导正确做事,不要冒犯
    • @fabb 同意你的看法。我会在以后的答案中关注您的建议,稍后我将使用更优化的答案编辑我的答案。 :)
    【解决方案4】:

    这就是我正在使用的。这样,如果警报已经显示, 我更喜欢用户关闭它而不是应用程序。 因此,如果视图已经显示警报,我只需等待 5 秒再试一次。

    我只是想补充一下,我没有测试太多,但它有效。(从我做的1个测试中),所以我希望我没有遗漏什么,因为我考虑了这个问题很长时间,并且这个解决方案听起来太简单了:)

    -(void) alertUserWithTitle:(NSString*) title Message:(NSString*) message
    {
        UIAlertController* alert = [UIAlertController alertControllerWithTitle:title                                                                              message:message
                                                                                preferredStyle:UIAlertControllerStyleAlert];
    
                        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                                              handler:^(UIAlertAction * action) {}];
    
                        [alert addAction:defaultAction];
    
                        if(self.presentedViewController == nil)
                        {
                            [self presentViewController:alert animated:YES completion:nil];
                        }else
                        {
                            double delayInSeconds = 2.0;
                            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    
                            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    
                                [self alertUserWithTitle:title Message:message];
    
                            });
    
                        }
    }
    

    【讨论】:

    • 适用于某些用例。如果警报应该阻止进一步的用户交互,那就不太理想了。
    【解决方案5】:

    这是我在 Swift 3 中使用的一个解决方案。它是一个向用户显示警报的函数,如果您在用户解除警报之前多次调用它,它会将新的警报文本添加到警报中已经呈现。如果正在呈现其他视图,则不会出现警报。并非所有人都同意这种行为,但它适用于简单的情况。

    extension UIViewController {
        func showAlert(_ msg: String, title: String = "") {
            if let currentAlert = self.presentedViewController as? UIAlertController {
                currentAlert.message = (currentAlert.message ?? "") + "\n\nUpdate:\(title): \(msg)"
                return
            }
    
            // create the alert
            let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
    
            // show the alert
            self.present(alert, animated: true, completion: nil)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多