场景:用户点击视图控制器上的按钮。视图控制器是导航堆栈中最顶层的(很明显)。tap调用在另一个类上调用的实用程序类方法。这里发生了不好的事情我想在控件返回到视图控制器之前在那里显示一个警告。
+ (void)myUtilityMethod {
// do stuff
// something bad happened, display an alert.
}
这是可能的UIAlertView(但可能不太合适)。
在这种情况下,你如何在myUtilityMethod中呈现UIAlertController ?
我尝试了上面提到的所有方法,但都没有成功。我在Swift 3.0中使用的方法:
extension UIAlertController {
func show() {
present(animated: true, completion: nil)
}
func present(animated: Bool, completion: (() -> Void)?) {
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
topController.present(self, animated: animated, completion: completion)
}
}
}
斯威夫特
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];
为了改进敏捷视觉的答案,你需要创建一个带有透明根视图控制器的窗口,并从那里显示警报视图。
然而,只要在警报控制器中有一个动作,就不需要保持对窗口的引用。作为动作处理程序块的最后一步,您只需要将窗口隐藏为清理任务的一部分。通过在处理程序块中有一个对窗口的引用,这将创建一个临时的循环引用,一旦警报控制器被解除,该引用将被打破。
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];
@agilityvision的答案翻译为Swift4/iOS11。我没有使用本地化字符串,但你可以很容易地改变:
import UIKit
/** An alert controller that can be called without a view controller.
Creates a blank view controller and presents itself over that
**/
class AlertPlusViewController: UIAlertController {
private var alertWindow: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.alertWindow?.isHidden = true
alertWindow = nil
}
func show() {
self.showAnimated(animated: true)
}
func showAnimated(animated _: Bool) {
let blankViewController = UIViewController()
blankViewController.view.backgroundColor = UIColor.clear
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = blankViewController
window.backgroundColor = UIColor.clear
window.windowLevel = UIWindowLevelAlert + 1
window.makeKeyAndVisible()
self.alertWindow = window
blankViewController.present(self, animated: true, completion: nil)
}
func presentOkayAlertWithTitle(title: String?, message: String?) {
let alertController = AlertPlusViewController(title: title, message: message, preferredStyle: .alert)
let okayAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okayAction)
alertController.show()
}
func presentOkayAlertWithError(error: NSError?) {
let title = "Error"
let message = error?.localizedDescription
presentOkayAlertWithTitle(title: title, message: message)
}
}