是否可以确定ViewController是否显示为Modal?


Answers:


96

由于modalViewControlleriOS 6中已弃用该版本,因此该版本适用于iOS 5+,并且可以在没有警告的情况下进行编译。

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

费利佩的答案的提示。


2
很好,我只是很长一段时间后才不得不再次使用它,并且注意到不赞成使用了...我编辑了答案,以便人们在使用iOS 6+时开始在这里寻找正确的代码,谢谢
Felipe Sabino

10
如果父视图控制器是推送视图控制器的模式,则该方法不起作用。
含义-

2
有一个错误,我们应该检查双方是否都为零,因为nil == nilreturn YES并不是我们想要的结果。
CocoaBob 2015年

1
@GabrielePetronella您是否介意我将答案更新为还包括该方法的Swift实现?
Michael瀑布

1
@MichaelWaterfall非常感谢,谢谢
Gabriele Petronella

77

如果您正在寻找iOS 6以上版本,则不建议使用此答案,您应该查看Gabriele Petronella的答案


作为UIKit固有的属性或方法,没有完美的方法可以做到这一点。您可以做的是检查控制器的多个方面,以确保将其显示为模态。

因此,要检查当前(以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;        

}

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

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

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


请记住,从modalViewControlleriOS 6开始不推荐使用该属性。文档建议改为使用presentedViewController
巴特·雅各布斯

@BartJacobs好点!我没有在iOS6发布后查看此答案,因此它可能不是最新的。tks,我将在本周晚些时候尝试进行一些测试以对其进行更新!
费利佩·萨比诺

NSLog(@"%@", self.navigationController.parentViewController)版画(null)-您能否解释原因?我的ViewController通过情节提要中的navController与模式视图控制器连接。
罗马

@oyatek您可以使用pastebin或类似的东西并显示一些代码吗?
Felipe Sabino 2014年

@Feilpe我发现了问题- .parentViewController已弃用,.presentingViewController必须改用。
罗马

35

在iOS5 +中,如UIViewController类参考中所见,您可以从属性“ presentingViewController”中获取它。

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

@property(非原子,只读)UIViewController * presentingViewController
讨论

如果接收到此消息的视图控制器由另一个视图控制器提供,则此属性将保存正在显示该消息的视图控制器。如果未显示视图控制器,但正在显示其祖先之一,则此属性将保留显示最近祖先的视图控制器。如果既不显示视图控制器也不显示其祖先,则此属性为nil。

可用性
在iOS 5.0和更高版本中可用。

UIViewController.h中声明


3
完美运行,使用if(self.presentingViewController){//这是一个模态viewContoller}否则{//这是一个普通的ViewController}
mashdup

2
恕我直言,这是这里唯一正确的答案。只需检查是否存在presentingViewController。它也将在容器视图控制器中工作,因为它会自动遍历祖先。
Daniel Rinser 2013年

17

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

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

您可以在viewWillAppear替代中检查此值。

我相信没有官方的属性可以说明视图的显示方式,但是没有什么可以阻止您创建自己的视图。


提示,这就是我所做的,但是我正在寻找其他一些整洁的解决方案。谢谢。
lukewar 2010年

如果您呈现UINavigationController为模式,则此解决方案不起作用...除非您创建仅用于添加此属性的自定义导航控制器。之后,在控制器内部,self.navigationController每次需要检查控制器是否显示为模态时,您都必须保持强制转换为该自定义类
Felipe Sabino

8

如果以模态形式显示self.navigationController,但self不等于self.navigationController.viewControllers [0],那么在这种情况下,将self推送,Petronella的答案将不起作用。

这是解决问题的方法。

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

6

这应该工作。

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

不幸的是,这不起作用。这是我的第一次尝试。但回到modalViewController INS零:(。
lukewar

如果仅获取“ self.parentViewController”,它是否返回正确的父对象?
kubi 2010年

4
问题可能在于您的UIViewController子类位于UINavigationController或UITabBarController(或两者)中,在这种情况下,您可能需要在视图层次结构中进行更多挖掘,以找出作为模态视图控制器呈现的父级。
hpique 2010年

@hgpc我需要这个CHCK在我的项目,所以我只是增加了一个答案,同时检查UINavigationControllerUITabBarController案件。到目前为止,它的运行情况还不错
Felipe Sabino

4

最好的检查方法

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

2

如果您不需要在全屏模式视图和非模式视图之间进行区分(在我的项目中就是这种情况(我正在处理仅在表单和页面表单中出现的问题),则可以使用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;
}

2

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
}

该用例存在问题。如果我在UINavigationController的根视图控制器中,它仍然会返回true,而不会出现任何模式表示。
mariusLAN

1
第一个if语句覆盖第二个if语句中的所有内容,从而使第二个语句多余。我不确定这里的意图是什么。
isoiphone

1

在我的项目中,我有一个视图控制器(详细信息),可以由主视图控制器以模态(添加新项目时)或通过推送(在编辑现有项目时)显示。当用户点击[Done]时,Detail视图控制器将调用Master视图控制器的方法来通知它已准备好关闭。大师必须确定如何呈现细节,以便知道如何将其关闭。这就是我的方法:

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

0

这样的黑客可能会起作用。

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
}

但是,我认为以前的答案是一种更干净的解决方案。


0

对我有用的是:

// 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上尝试过。


0

我四处张望,找到了这个问题的正确答案,但找不到涵盖所有可能情况的任何答案。我写了几行似乎可以完成工作的代码。您可以找到一些内联注释来找出已检查的内容。

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

希望能有所帮助。


0

这是isModal@GabrielePetronella 的修改后的版本,可与包含的视图控制器一起使用,因为它首先沿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
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.