如何从 Appdelegate 显示 UIAlertController
Posted
技术标签:
【中文标题】如何从 Appdelegate 显示 UIAlertController【英文标题】:How to show UIAlertController from Appdelegate 【发布时间】:2016-03-22 13:31:25 【问题描述】:我正在 ios 应用上使用 PushNotification。我想在应用收到通知时显示 UIalertcontroller。
我在 AppDelegate 中尝试以下代码:
[self.window.rootViewController presentViewController:alert animated:YES completion:nil];
但 UIAlertcontroller 显示在根视图(第一个屏幕)中,对于其他 uiviewcontroller,我收到警告或应用程序崩溃。
【问题讨论】:
崩溃报告是什么 但是 UIAlertcontroller 显示在根视图中......当然您正在将警报添加到根控制器。当然,它会在其他 uiview 控制器上崩溃,因为您正在尝试在控制器上添加警报,而该警报未向用户显示。 是的,我知道我正在将 uialertcontroller 添加到 rootView 而不是活动视图,我的问题是如何在收到通知时在另一个 uiviewcontroller 中显示 uialertController。 【参考方案1】:试试这个
Objective-C
UIWindow* topWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
topWindow.rootViewController = [UIViewController new];
topWindow.windowLevel = UIWindowLevelAlert + 1;
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"APNS" message:@"received Notification" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK",@"confirm") style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action)
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.hidden = YES; // if you want to hide the topwindow then use this
topWindow = nil; // if you want to remove the topwindow then use this
]];
[topWindow makeKeyAndVisible];
[topWindow.rootViewController presentViewController:alert animated:YES completion:nil];
Swift3 及以上版本
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindow.Level.alert + 1
let alert = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel) _ in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow?.isHidden = true // if you want to hide the topwindow then use this
topWindow = nil // if you want to hide the topwindow then use this
)
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion: nil)
详细说明:http://www.thecave.com/2015/09/28/how-to-present-an-alert-view-using-uialertcontroller-when-you-dont-have-a-view-controller/
【讨论】:
我将如何为 swift 3 添加另一个按钮到 UIAlert 创建UIAlertAction的对象并处理动作 @JohnyDGood - 查看此内容以了解多项操作***.com/questions/35152650/… @Anbu.karthik 我想创建一个新窗口来显示警报不是一个好方法,代码只是隐藏窗口而不是完全删除它。如果我错了,你能纠正我吗? @TheTiger-感谢前辈的宝贵意见,我根据我回答的ARC概念更新了答案【参考方案2】:最短且最简单的:
创建一个扩展:
extension UIApplication
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController?
if let navigationController = controller as? UINavigationController
return topViewController(controller: navigationController.visibleViewController)
if let tabController = controller as? UITabBarController
if let selected = tabController.selectedViewController
return topViewController(controller: selected)
if let presented = controller?.presentedViewController
return topViewController(controller: presented)
return controller
然后在任何地方使用它
UIApplication.topViewController()?.present(UIViewController, animated: true, completion: nil)
有了它,您可以在任何地方显示警报或任何内容 示例:
let alert = UIAlertController(title: "Your title", message: "Your message", preferredStyle: .alert)
let cancelButton = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(cancelButton)
UIApplication.topViewController()?.present(alert, animated: true, completion: nil)
替代方法:
无需创建任何扩展或任何方法或任何东西,只需编写以上 3 行来创建警报和呈现使用:
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
就是这样! =)
【讨论】:
【参考方案3】:Anbu.Karthik's answer 但在 斯威夫特 4.1
var topWindow: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
topWindow?.rootViewController = UIViewController()
topWindow?.windowLevel = UIWindowLevelAlert + 1
let alert: UIAlertController = UIAlertController(title: "APNS", message: "received Notification", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: (alertAction) in
topWindow?.isHidden = true
topWindow = nil
))
topWindow?.makeKeyAndVisible()
topWindow?.rootViewController?.present(alert, animated: true, completion:nil)
感谢您阅读本文。
【讨论】:
【参考方案4】:斯威夫特 4.1 您可以使用以下代码从 AppDelegate 显示警报
func showAlertFromAppDelegates()
let alertVC = UIAlertController(title: "Oops" , message: "Presented Alert from AppDelegates", preferredStyle: UIAlertControllerStyle.alert)
let okAction = UIAlertAction(title: "Okay", style: UIAlertActionStyle.cancel) (alert) in
exit(0) // Your code here
alertVC.addAction(okAction)
DispatchQueue.main.async
var presentVC = self.window?.rootViewController
while let next = presentVC?.presentedViewController
presentVC = next
presentVC?.present(alertVC, animated: true, completion: nil)
【讨论】:
这对我很有用!起初我认为指令是将这个函数放在实际的 appDelegate 中,但我能够将它放在启动图像上传的视图控制器中,这使我能够在他们关闭该视图控制器后显示此警报。谢谢! 警报出现两次【参考方案5】:为了方便,我使用了分类
UIAlertController+UIWindow.h
@interface UIAlertController (UIWindow)
- (void)show;
- (void)show:(BOOL)animated;
@end
UIAlertController+UIWindow.m
#import <objc/runtime.h>
@interface UIAlertController (Private)
@property (nonatomic, strong) UIWindow *alertWindow;
@end
@implementation UIAlertController (Private)
@dynamic alertWindow;
- (void)setAlertWindow:(UIWindow *)alertWindow
objc_setAssociatedObject(self, @selector(alertWindow), alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (UIWindow *)alertWindow
return objc_getAssociatedObject(self, @selector(alertWindow));
@end
@implementation UIAlertController (UIWindow)
- (void)show
[self show:YES];
- (void)show:(BOOL)animated
[self setupWindow];
[self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
- (void)setupWindow
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
if ([delegate respondsToSelector:@selector(window)])
self.alertWindow.tintColor = delegate.window.tintColor;
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
- (void)viewDidDisappear:(BOOL)animated
[super viewDidDisappear:animated];
// precaution to insure window gets destroyed
self.alertWindow.hidden = YES;
self.alertWindow = nil;
使用:
UIAlertController *alertController;
// -- code --
[alertController show];
【讨论】:
【参考方案6】:我写了一个静态类,让代码在 swift 4 中可重用,这个类提供了不同的方法来显示警报。
class AlertUtility: NSObject
static func showAlert(title: String!, message : String!, viewController: UIViewController)
let alert = UIAlertController(title: title, message: message ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
static func showAlertAutoDismiss(title: String!, message : String!) -> Void
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 0.8
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: )
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when)
// your code with delay
alert.dismiss(animated: true, completion: nil)
topWindow.isHidden = true
// Show alert view with call back
static func showAlertWithCB(title: String, message: String, isConditional: Bool, viewController: UIViewController, completionBlock: @escaping (_: Bool) -> Void)
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
// Check whether it's conditional or not ('YES' 'NO, or just 'OK')
if isConditional
alert.addAction(UIAlertAction(title: NSLocalizedString("yes", comment: ""), style: UIAlertActionStyle.default, handler: (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
))
alert.addAction(UIAlertAction(title: NSLocalizedString("no", comment: ""), style: UIAlertActionStyle.default, handler: (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(false)
))
else
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.default, handler: (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
))
viewController.present(alert, animated: true, completion: nil)
static func showAlert(title: String!, message : String!) -> Void
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 1
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: )
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: (_ action: UIAlertAction) -> Void in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.isHidden = true
))
static func showComingSoon(viewController: UIViewController)
let alert = UIAlertController(title: "", message: "Coming Soon", preferredStyle: .alert)
viewController.present(alert, animated: true, completion: )
// change to desired number of seconds (in this case 1 seconds)
let when = DispatchTime.now() + 0.6
DispatchQueue.main.asyncAfter(deadline: when)
// your code with delay
alert.dismiss(animated: true, completion: nil)
static func showGenericErrorMessageAlert(viewController: UIViewController)
let alert = UIAlertController(title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("generic.error.message", comment: "") ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
viewController.present(alert, animated: true, completion: nil)
static func showAlertWithTextField(viewController : UIViewController,completionBlock: @escaping (_: Bool, String) -> Void)
//1. Create the alert controller.
let alert = UIAlertController(title: "Report Event?", message: "", preferredStyle: .alert)
alert.view.tintColor = APP_ORANGE_COLOR
//2. Add the text field. You can configure it however you need.
//AlertUtility.addte
alert.addTextField (textField) in
let heightConstraint = NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
textField.addConstraint(heightConstraint)
textField.placeholder = "Enter report reason here"
textField.tintColor = APP_ORANGE_COLOR
textField.autocapitalizationType = .sentences
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: (_) in
// Force unwrapping because we know it exists.
completionBlock(true,"")
//print("Text field: \(textField.text)")
))
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Submit", style: .default, handler: [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
completionBlock(true,(textField?.text)!)
//print("Text field: \(textField.text)")
))
// 4. Present the alert.
viewController.present(alert, animated: true, completion: nil)
let textField = alert.textFields![0]
let v = UIView.init(frame: textField.frame)
textField.addSubview(v)
v.frame = textField.frame
v.bounds = textField.bounds
v.backgroundColor = APP_ORANGE_COLOR
v.superview?.bringSubview(toFront: v)
【讨论】:
以上是关于如何从 Appdelegate 显示 UIAlertController的主要内容,如果未能解决你的问题,请参考以下文章
IOS 从 AppDelegate 中的 addMessageFromRemoteNotification 显示 UIViewController
如何从 appDelegate 呈现 UIAlertView