简体   繁体   中英

Determining if a UIViewController is being presented modally

My application's main window contains a xib-based UITabBarController (fully configured in Interface Builder) that can also be presented modally (much like the Music.app "Add songs to playlist" modal view). The UITabBarController contains a number of UINavigationControllers which in turn contain subclassed UITableViewControllers. This is how I'm currently detecting if the subclassed UITableViewController is being presented inside a modal UITabBarController:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.isModal = NO;

    UIViewController *child     = self;
    UIViewController *parent    = self.parentViewController;
    while (parent) {
        if (parent.modalViewController && parent.modalViewController == child) {
            self.isModal = YES;
            break;
        }
        child   = parent;
        parent  = parent.parentViewController;
    }

    if (self.isModal) {
        // modal additions, eg. Done button, navigationItem.prompt
    }
    else {
        // normal additions, eg. Now Playing button
    }
}

Is there a way to do this that doesn't involve walking up the parentViewController tree or subclassing all the intermediate view controllers to pass down the isModal state when they are initialized?

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


I answered a very similar question a while ago, where I have a function to determine whether the current controller is presented as modal or not, without the need to subclass the tab bar controller here:

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

At the original answer there are some basic explanations on how this function works and you cancheck there if needed, but here it is

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

}

Since iOS5 you can also use isBeingPresented on a viewController instance:

- (BOOL)isModalViewController
{
    return [self isBeingPresented];
}

Got an answer on Twitter . I ended up subclassing UITabBarController and adding a BOOL isModal instance property which is set to YES when presenting modally. Then subviews can use self.tabBarController with a cast to the subclass to access the isModal property and render/behave accordingly.

I'd look at getting the root view controller and checking if it has a modal view controller. You can get that view controller from UIWindow. Note also that you can iterate through the current view controller's hierarchy using UINavigationController's viewControllers property: for (UIViewController *viewController in self.navigationController.viewControllers) { ... } is faster and simpler.

You could set the display state in a custom initialiser when you present the view. I mean the code presenting it will know how it's being presented, right?

- (void)initInModalMode:(BOOL)isModal

It's better than having the view retroactively discover its status later on?

There is a much easier way in these Swift days.

extension UIViewController {

    var isPresentedModally: Bool {
        return presentingViewController?.presentedViewController == self || parent?.isPresentedModally == true
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM