Is it possible to determine whether ViewController is presented as Modal?

后端 未结 14 2011
一生所求
一生所求 2020-12-04 07:13

Is it possible to check inside ViewController class that it is presented as modal view controller?

相关标签:
14条回答
  • 2020-12-04 07:49

    In my project I have a view controller (Detail) that can be presented either modally (when adding a new item) or with push (when editing an existing one) by Master view controller. When user taps [Done] the Detail view controller calls Master view controller's method to notify that it is ready to be closed. Master has to determine how Detail is presented in order to know how to close it. This is how I do this:

    UIViewController *vc = self.navigationController.viewControllers.lastObject;
    if (vc == self) {
        [self dismissViewControllerAnimated:YES completion:NULL];
    } else {
        [self.navigationController popViewControllerAnimated:YES];
    }
    
    0 讨论(0)
  • 2020-12-04 07:51

    Petronella's answer does not work if self.navigationController is modally presented but self is not equal to self.navigationController.viewControllers[0], in that case self is pushed.

    Here is how you could fix the problem.

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

    And in 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
    
    0 讨论(0)
  • 2020-12-04 07:52

    If there isn't, you can define a property for this (presentedAsModal) in your UIViewController subclass and set it to YES before presenting the ViewController as a modal view.

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

    You can check this value in your viewWillAppear override.

    I believe there isn't an official property that states how the view is presented, but nothing prevents you from creating your own.

    0 讨论(0)
  • 2020-12-04 07:55

    If you a looking for iOS 6+, this answer is deprecated and you should check Gabriele Petronella's answer


    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.

    So, to check if the current (represented as self in the code bellow) controller is presented in a modal way or not, I have the function bellow either in a UIViewController category, or (if your project does not need to use other UIKit controllers, as UITableViewController for example) in a base controller that my other controllers inherit of

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

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

    EDIT 2: added iOS 5+ check, where UIViewController does not answer for parentViewController anymore, but to presentingViewController instead.

    EDIT 3: I've created a gist for it just in case https://gist.github.com/3174081

    0 讨论(0)
  • 2020-12-04 08:01

    In iOS5+, As you can see in UIViewController Class Reference, you can get it from property "presentingViewController".

    presentingViewController The view controller that presented this view controller. (read-only)

    @property(nonatomic, readonly) UIViewController *presentingViewController
    Discussion

    If the view controller that received this message is presented by another view controller, this property holds the view controller that is presenting it. If the view controller is not presented, but one of its ancestors is being presented, this property holds the view controller presenting the nearest ancestor. If neither the view controller nor any of its ancestors are being presented, this property holds nil.

    Availability
    Available in iOS 5.0 and later.
    Declared In
    UIViewController.h

    0 讨论(0)
  • 2020-12-04 08:02

    I've looked a bit around to find the right answer to this question, and I couldn't find any which covered all the possible scenarios. I wrote these few lines of code which seem to do the job. You can find few inline comments to figure out what's been checked.

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

    Hope this help.

    0 讨论(0)
提交回复
热议问题