场景:用户点击视图控制器上的按钮。视图控制器是导航堆栈中最顶层的(很明显)。tap调用在另一个类上调用的实用程序类方法。这里发生了不好的事情我想在控件返回到视图控制器之前在那里显示一个警告。

+ (void)myUtilityMethod {
    // do stuff
    // something bad happened, display an alert.
}

这是可能的UIAlertView(但可能不太合适)。

在这种情况下,你如何在myUtilityMethod中呈现UIAlertController ?


当前回答

斯威夫特5

我刚刚创建了一个新窗口,并在其中添加了警报视图控制器。

查看类TopViewController:

https://gist.github.com/odnaks/3f3fd0d20f318c6276e76d0f9d7de5a7

我使用它很简单,像UIAlertController:

 let alert = TopAlertController()
 alert.title = "title"
 alert.message = "message"
 alert.addAction(UIAlertAction(title: "Ок", style: .default, handler: { _ in }))
 alert.show()

其他回答

为了改进敏捷视觉的答案,你需要创建一个带有透明根视图控制器的窗口,并从那里显示警报视图。

然而,只要在警报控制器中有一个动作,就不需要保持对窗口的引用。作为动作处理程序块的最后一步,您只需要将窗口隐藏为清理任务的一部分。通过在处理程序块中有一个对窗口的引用,这将创建一个临时的循环引用,一旦警报控制器被解除,该引用将被打破。

UIWindow* window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
window.rootViewController = [UIViewController new];
window.windowLevel = UIWindowLevelAlert + 1;

UIAlertController* alertCtrl = [UIAlertController alertControllerWithTitle:... message:... preferredStyle:UIAlertControllerStyleAlert];

[alertCtrl addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK",@"Generic confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    ... // do your stuff

    // very important to hide the window afterwards.
    // this also keeps a reference to the window until the action is invoked.
    window.hidden = YES;
}]];

[window makeKeyAndVisible];
[window.rootViewController presentViewController:alertCtrl animated:YES completion:nil];

几个月前我发过一个类似的问题,我想我终于解决了这个问题。如果你只是想看代码,请点击我文章底部的链接。

解决方案是使用一个额外的UIWindow。

当你想要显示你的UIAlertController:

使你的窗口成为键和可见窗口(window. makekeyandvisible ()) 只需使用一个普通的UIViewController实例作为新窗口的rootViewController。(窗口。rootViewController = UIViewController()) 在你窗口的rootViewController上显示你的UIAlertController

有几点需要注意:

你的UIWindow必须是强引用的。如果它没有被强引用,它将永远不会出现(因为它已经被释放了)。我建议使用属性,但我也成功地使用了关联对象。 为了确保窗口显示在其他所有内容之上(包括系统UIAlertControllers),我设置了windowLevel。(窗口。windowLevel = UIWindowLevelAlert + 1)

最后,我有一个完整的实现,如果你只是想看看。

https://github.com/dbettermann/DBAlertController

下面的解决方案没有发挥作用,尽管它在所有版本中看起来都很有前途。这个解决方案正在生成WARNING。

警告:试图显示不在窗口层次结构中的视图!

https://stackoverflow.com/a/34487871/2369867 = > 这在当时看起来很有希望。但在Swift 3中没有。 所以我在Swift 3中回答这个问题,这不是模板示例。

一旦粘贴到任何函数中,这是相当完整的功能代码。

快速Swift 3自包含代码

let alertController = UIAlertController(title: "<your title>", message: "<your message>", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.cancel, handler: nil))

let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)

这是在Swift 3中测试和工作的代码。

这在Swift中适用于普通的视图控制器,即使屏幕上有一个导航控制器:

let alert = UIAlertController(...)

let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.presentViewController(alert, animated: true, completion: nil)

斯威夫特

let alertController = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
//...
var rootViewController = UIApplication.shared.keyWindow?.rootViewController
if let navigationController = rootViewController as? UINavigationController {
    rootViewController = navigationController.viewControllers.first
}
if let tabBarController = rootViewController as? UITabBarController {
    rootViewController = tabBarController.selectedViewController
}
//...
rootViewController?.present(alertController, animated: true, completion: nil)

objective - c

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"message" preferredStyle:UIAlertControllerStyleAlert];
//...
id rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
if([rootViewController isKindOfClass:[UINavigationController class]])
{
    rootViewController = ((UINavigationController *)rootViewController).viewControllers.firstObject;
}
if([rootViewController isKindOfClass:[UITabBarController class]])
{
    rootViewController = ((UITabBarController *)rootViewController).selectedViewController;
}
//...
[rootViewController presentViewController:alertController animated:YES completion:nil];