是否有可能确定ViewController是否呈现为Modal?

是否有可能检查内部ViewController类,它是作为模态视图控制器呈现?

由于modalViewController已经在iOS 6中被弃用,这里是一个适用于iOS 5+的版本,可以在没有警告的情况下编译。

Objective-C的:

 - (BOOL)isModal { return self.presentingViewController.presentedViewController == self || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController) || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]]; } 

迅速:

 var isModal: Bool { return self.presentingViewController?.presentedViewController == self || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) || self.tabBarController?.presentingViewController is UITabBarController } 

帽子给菲利普的答案。

如果你正在寻找iOS 6+,这个答案已被弃用,你应该检查Gabriele Petronella的答案


作为UIKit原生的属性或方法,没有简单的方法来做到这一点。 你可以做的是检查你的控制器的几个方面,以确保它呈现为模态。

所以,为了检查当前 (在下面的代码中表示为self )是否以模态方式呈现,我在UIViewController类中有下面的函数,或者(如果你的项目不需要使用其他的UIKit控制器,例如UITableViewController )在我的其他控制器inheritance的基础控制器

 -(BOOL)isModal { BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) || //or if I have a navigation controller, check if its parent modal view controller is self navigation controller ( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) || //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation [[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]); //iOS 5+ if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) { isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) || //or if I have a navigation controller, check if its parent modal view controller is self navigation controller (self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) || //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation [[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]); } return isModal; } 

编辑:我添加了最后一次检查,看看是否正在使用UITabBarController,并呈现另一个UITabBarController为模态。

编辑2:添加iOS 5 +检查,其中UIViewController不再回答parentViewController ,而是parentViewController

编辑3:我已经创build了一个要点,以防万一https://gist.github.com/3174081

在iOS5 +中,正如你可以在UIViewController类参考中看到的那样,你可以从属性“presentsViewController”中获得它。

presentsViewController呈现此视图控制器的视图控制器。 (只读)

@属性(非primefaces,只读)UIViewController * presentsViewController
讨论

如果接收到此消息的视图控制器由另一个视图控制器呈现,则此属性保存呈现该视图的视图控制器。 如果视图控制器没有被呈现,但是其祖先之一被呈现,则该属性使视图控制器呈现最近的祖先。 如果视图控制器或其任何祖先都没有呈现,则该属性为零。

可用性
在iOS 5.0及更高版本中可用。
宣布在
UIViewController.h

如果没有,你可以在你的UIViewController子类中为这个( presentedAsModal )定义一个属性,并在将ViewController作为模态视图呈现之前将其设置为YES

 childVC.presentedAsModal = YES; [parentVC presentModalViewController:childVC animated:YES]; 

你可以在你的viewWillAppear覆盖中检查这个值。

我相信没有一个官方的财产陈述观点如何呈现,但没有任何东西阻止你创build自己的观点。

Petronella的答案不工作,如果self.navigationController模态呈现,但self不等于self.navigationController.viewControllers [0],在这种情况下,自我推。

这是你如何解决这个问题。

 return self.presentingViewController.presentedViewController == self || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0]) || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]]; 

而在Swift中:

 return self.presentingViewController?.presentedViewController == self || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self) || self.tabBarController?.presentingViewController is UITabBarController 

这应该工作。

 if(self.parentViewController.modalViewController == self)… 

最好的方法来检查

  if (self.navigationController.presentingViewController) { NSLog(@"Model Present"); } 

如果您不需要区分全屏模态视图和非模态视图(这是我的项目中的情况(我正在处理仅在表单和页面中出现的问题),则可以使用modalPresentationStyle UIViewController的属性:

 switch (self.modalPresentationStyle) { case 0: NSLog(@"full screen, or not modal"); break; case 1: NSLog(@"page sheet"); break; case 2: NSLog(@"form sheet"); break; } 

Swift中

 func isUIViewControllerPresentedAsModal() -> Bool { if((self.presentingViewController) != nil) { return true } if(self.presentingViewController?.presentedViewController == self) { return true } if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) { return true } if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) { return true } return false } 

在我的项目中,我有一个视图控制器(细节),可以通过主视图控制器以模态方式(添加新项目时)或按下(编辑现有项目时)。 当用户点击[完成]时,细节视图控制器调用主视图控制器的方法来通知它已准备好closures。 大师必须确定如何呈现细节以便知道如何closures它。 这是我如何做到这一点:

 UIViewController *vc = self.navigationController.viewControllers.lastObject; if (vc == self) { [self dismissViewControllerAnimated:YES completion:NULL]; } else { [self.navigationController popViewControllerAnimated:YES]; } 

像这样的黑客可能工作。

 UIViewController* child = self; UIViewController* parent = child.parentViewController; while (parent && parent.modalViewController != child) { child = parent; parent = child.parentViewController; } if (parent) { // A view controller in the hierarchy was presented as a modal view controller } 

不过,我想我以前的答案是一个更清洁的解决scheme。

以下是对我有用的东西:

 // this is the trick: set parent view controller as application's window root view controller UIApplication.sharedApplication.delegate.window.rootViewController = viewController; // assert no modal view is presented XCTAssertNil(viewController.presentedViewController); // simulate button tap which shows modal view controller [viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside]; // assert that modal view controller is presented XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class); 

据我testing,这适用于iOS7和iOS8。 但是没有尝试在iOS6上。

我看了一下,find了这个问题的正确答案,我找不到任何可能的情况。 我写了这几行代码似乎做了这项工作。 你可以find几个内联的评论来找出已经被检查的内容。

 - (BOOL)isModal { BOOL modal = NO; if ([self presentingViewController]) { //Some view Controller is presenting the current stack UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack NSArray *viewControllers = [presented performSelector:@selector(viewControllers)]; modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack } else { modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho. } } return modal; } 

希望这个帮助。

这里是我的修改版本@ GabrielePetronella的isModal ,它与包含的视图控制器一起工作,因为它首先遍历parentViewController层次结构。 也把代码分成多行,清楚它在做什么。

 var isModal: Bool { // If we are a child view controller, we need to check our parent's presentation // rather than our own. So walk up the chain until we don't see any parentViewControllers var potentiallyPresentedViewController : UIViewController = self while (potentiallyPresentedViewController.parentViewController != nil) { potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController! } if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController { return true } if let navigationController = potentiallyPresentedViewController.navigationController { if navigationController.presentingViewController?.presentedViewController == navigationController { return true } } return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController }