是否可以确定 ViewController 是否以 Modal 的形式出现?

是否可以在 ViewController 类中检查它是否表示为模态视图控制器?

62030 次浏览

如果没有,可以在 UIViewController 子类中为此定义一个属性(presentedAsModal) ,并将其设置为 YES,然后将 ViewController 显示为模态视图。

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

您可以在 viewWillAppear重写中检查此值。

我相信没有一个官方的财产说明视图是如何呈现的,但没有什么能阻止你创建自己的视图。

This should work.

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

这样的黑客手段也许能行。

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
}

然而,我认为我以前的答案是一个更干净的解决方案。

如果你正在寻找 iOS6 + ,这个答案是不推荐的,你应该选择 Gabriele Petronella 的回答


There is no neat way to do that, as a property or method native to UIKit. What you can do is to check several aspects of your controller to ensure it is presented as modal.

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

-(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;


}

编辑: I added the last check to see if a UITabBarController is being used, and you present another UITabBarController as modal.

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

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

如果你不需要区分全屏模态视图和非模态视图,我的项目就是这种情况(我正在处理一个只有表单和页面表单才会出现的问题) ,你可以使用 UIViewController 的 modalPresentationStyle 属性:

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

在 iOS5 + 中,正如您在 类引用中看到的,您可以从属性“ presingViewController”获得它。

呈现 ViewController 显示此视图控制器的视图控制器。(只读)

@ property (非原子,readonly) UIViewController * presingViewController
讨论 < br/>

如果接收此消息的视图控制器由另一个视图控制器提供,则此属性保存提供该消息的视图控制器。如果未显示视图控制器,但显示了其祖先之一,则此属性保存显示最近祖先的视图控制器。如果既没有显示视图控制器,也没有显示它的任何祖先,则此属性为空。

可用性
可在 iOS 5.0及更高版本中使用。
Declared In
UIViewController.h

由于 modalViewController在 iOS6中已经被弃用,这里有一个版本可以在 iOS5 + 中使用,并且可以在没有警告的情况下编译。

目标 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
}

费利佩回答的帽尖。

最好的检查方法

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

对我起作用的是:

// 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);

就我测试的情况来看,它适用于 iOS7和 iOS8,但是没有在 iOS6上试用过。

斯威夫特:

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
}

在我的项目中,我有一个视图控制器(详细信息) ,它可以通过主视图控制器模式化地(在添加新项目时)或者通过 push (在编辑现有项目时)显示。当用户点击[完成]详细视图控制器调用主视图控制器的方法来通知它已经准备好被关闭。为了知道如何关闭它,Master 必须确定 Detail 是如何显示的。我是这么做的:

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

为了找到这个问题的正确答案,我四处寻找了一下,但是没有找到一个能够涵盖所有可能情况的答案。我写的这几行代码似乎可以完成这项工作。您可以找到一些内联注释来确定检查了哪些内容。

- (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;
}

希望这个能帮上忙。

Petronella 的回答 不起作用,如果 self. NavigationController 是模态表示的,但 self 不等于 self. NavigationController.viewControllers [0] ,在这种情况下,self 是被推动的。

以下是您解决这个问题的方法。

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]];

在斯威夫特:

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

这是我修改后的@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
}