场景:用户点击视图控制器上的按钮。视图控制器是导航堆栈中的最顶层(显然)。tap调用在另一个类上调用的实用程序类方法。那里发生了一件坏事,我想在控件返回视图控制器之前在那里显示一个警报。
+ (void)myUtilityMethod {
// do stuff
// something bad happened, display an alert.
}
这在UIAlertView
中是可能的(但可能不太合适)。
在这种情况下,您如何呈现一个UIAlertController
,就在myUtilitymethod
中?
您可以使用Swift 2.2执行以下操作:
let alertController: UIAlertController = ...
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil)
和Swift 3.0:
let alertController: UIAlertController = ...
UIApplication.shared.keyWindow?.rootViewController?.present(alertController, 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)
目标-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];
在WWDC,我在一个实验室停下来,问了苹果工程师同样的问题:“显示UIAlertController的最佳实践是什么?”他说他们经常收到这个问题,我们开玩笑说他们应该就此开个会。他说,苹果内部正在创建一个UIWindow
,带有透明的UIViewController
,然后在上面呈现UIAlertController
。基本上迪伦·贝特曼的答案是什么。
但是我不想使用UIAlertController的子类,因为这需要我在整个应用程序中更改代码。因此,在关联对象的帮助下,我在UIAlertController上创建了一个类别,该类别在Objecte-C中提供了一个show方法。
以下是相关代码:
#import "UIAlertController+Window.h"
#import <objc/runtime.h>
@interface UIAlertController (Window)
- (void)show;
- (void)show:(BOOL)animated;
@end
@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 (Window)
- (void)show {
[self show:YES];
}
- (void)show:(BOOL)animated {
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
// Applications that does not load with UIMainStoryboardFile might not have a window property:
if ([delegate respondsToSelector:@selector(window)]) {
// we inherit the main window's tintColor
self.alertWindow.tintColor = delegate.window.tintColor;
}
// window level is above the top window (this makes the alert, if it's a sheet, show over the keyboard)
UIWindow *topWindow = [UIApplication sharedApplication].windows.lastObject;
self.alertWindow.windowLevel = topWindow.windowLevel + 1;
[self.alertWindow makeKeyAndVisible];
[self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// precaution to ensure window gets destroyed
self.alertWindow.hidden = YES;
self.alertWindow = nil;
}
@end
下面是一个示例用法:
// need local variable for TextField to prevent retain cycle of Alert otherwise UIWindow
// would not disappear after the Alert was dismissed
__block UITextField *localTextField;
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Global Alert" message:@"Enter some text" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSLog(@"do something with text:%@", localTextField.text);
// do NOT use alert.textfields or otherwise reference the alert in the block. Will cause retain cycle
}]];
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
localTextField = textField;
}];
[alert show];
解除分配UIAlertController
时,创建的UIWindow
将被销毁,因为它是唯一保留UIWindow
的对象。但是,如果您将UIAlertController
分配给属性,或通过访问其中一个操作块中的警报使其保留计数增加,则UIWindow
将保持在屏幕上,锁定您的UI。如果需要访问UITextField
,请参阅上面的示例使用代码。
我用一个测试项目做了一个GitHub回购: FFGlobalAlertController
问题内容: 我有一个非标准的Spring MVC项目。用XML响应。是否可以创建一个视图(jsp页面),以显示所有接受的(不是必需的)控制器,映射和参数。 根据答案,我有: 我没有得到任何信息 问题答案: 随着Spring 3.1,你可以轻松浏览端点。 The controller : The view : 你也可以在Spring <3.1中使用代替。但是你不会获得相同级别的信息。 有了它们,你将
问题内容: 我正在构建一个带有angular + ionic的应用程序,该应用程序在底部使用一个经典的三按钮菜单,其中包含三个ion- tabs。用户单击选项卡时,该模板通过ui-router打开。 我有这样的状态: 在模板中,我执行以下操作: 我知道我可以在控制器中编写doSomething()函数,并在那里手动调用它。那给了我同样的问题。每当有人打开该视图时,我似乎都无法弄清楚如何调用doSo
比方说,我有一个名为VC2的视图控制器类的实例。在VC2中,有一个“cancel”(取消)按钮会自动关闭。但当“取消”按钮触发时,我无法检测或接收任何回调。VC2是一个黑匣子。 视图控制器(称为VC1)将使用呈现视图控制器:动画:完成方法呈现VC2。 VC1在VC2被解除时必须检测哪些选项? 编辑:从@rory mckinnel的评论和@NicolasMiari的回答中,我尝试了以下方法: 在VC
我有一个导航视图控制器,它会在操作时向选项卡栏视图控制器发送一个序列。因此,选项卡式视图控制器继承了导航栏。我正在尝试将标题应用于连接到选项卡栏视图控制器的其中一个视图控制器,但通过代码设置标题对我不起作用。有人知道为什么会这样吗? 这是我的故事板的图片: 带有注销按钮的视图控制器是我试图在导航条(代码)中设置标题的地方: 导航控制器中嵌入的视图控制器触发到选项卡栏控制器的顺序:
问题内容: 我正在使用presentViewController呈现新屏幕 这将显示从下到上的新屏幕,但我希望不使用即可从右到左显示。 我使用的是Xib而不是情节提要,该怎么办? 问题答案: 是否使用或正在使用都没有关系。通常,当您将视图控制器推入Presentor时,使用从右向左过渡。 更新 新增计时功能 示例项目与 斯威夫特4 实现加入GitHub上 迅捷3和4.2 对象 斯威夫特2.x 在自
我的项目中有多个故事板。我在一个故事板中有一个主页面浏览量控制器,我在一个单独的故事板中有一个安装视图控制器嵌入导航控制器。现在,当我从主页视图控制器中显示安装视图控制器导航控制器时,状态栏不会隐藏。但是当我将安装视图控制器故事板设置为info.plist中的主故事板文件库,并且安装视图控制器导航控制器是第一个呈现的视图时,状态栏将隐藏。我正在使用下面的代码隐藏状态栏。有人能告诉我当状态视图控制器