判断一个UIViewController是否以模态方式呈现

9

我的应用程序主窗口包含一个基于xib的UITabBarController(在Interface Builder中完全配置),也可以以模态方式呈现(类似于Music.app“添加歌曲到播放列表”模态视图)。 UITabBarController包含许多UINavigationController,这些导航控制器又包含了子类化的UITableViewControllers。以下是我目前检测子类化的UITableViewController是否在模态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
    }
}

有没有一种方法可以不涉及遍历parentViewController树或子类化所有中间视图控制器来传递isModal状态,而实现这个目标呢?
6个回答

10
如果您正在寻找 iOS 6+,那么此答案已经过时,您应该查看 Gabriele Petronella 的回答
我之前回答过一个非常相似的问题,其中我有一个函数可以确定当前控制器是否以模态方式呈现,而无需在此处子类化选项卡栏控制器: 有没有可能确定ViewController是否作为Modal呈现? 原始答案中有一些基本的解释,如果需要可以在那里检查,但这里是:
-(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;        

}

5

自iOS5起,您还可以在viewController实例上使用isBeingPresented

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

4

在Twitter上获得了一个答案。我最终通过子类化UITabBarController并添加一个BOOL类型的isModal实例属性来解决问题,当以模态方式呈现时将其设置为YES。然后,子视图可以使用self.tabBarController并将其转换为子类来访问isModal属性并相应地渲染/行为。


3
向子类进行转型。这似乎有些别扭。为什么要使用子类?为什么不向UITabBarController添加一个包含isModal的类别? - Erik Engheim

2

我会查找根视图控制器并检查它是否有模态视图控制器。您可以从UIWindow获取该视图控制器。还要注意,您可以使用UINavigationController的viewControllers属性遍历当前视图控制器的层次结构:for (UIViewController *viewController in self.navigationController.viewControllers) { ... } 更快更简单。


我不明白这两个建议如何与我的问题相关(并不是说它们不相关,只是我不理解)。如果UIWindow > UITabBarController > UINavigationBarController > ACustomTableViewController中的一个按钮以模态方式呈现相同的UITabBarController层次结构,那么UIWindow中的根UITabBarController控制器如何知道发生了什么?关于self.navigationController.viewControllers,它是否只包含当前navigationController中的层次结构?在呈现相同UITabBarController的单独实例的模态视图中,它如何帮助我? - Shaun Inman
当您加载UITabBarController时,如果它是当前UIWindow的rootViewController,则不会将Done按钮放在UI中。否则,它将位于该rootViewController之上(可能是模态的,但您应该检查以确保)。您正在考虑当前视图层次结构... - chockenberry
关于迭代查看控制器的另一个评论只是为了向您展示您不需要检查父项等。这并不能解决如何确定您是否模态的问题。 - chockenberry

1

当您呈现视图时,可以在自定义初始化程序中设置显示状态。我的意思是呈现它的代码将知道它是如何被呈现的,对吧?

- (void)initInModalMode:(BOOL)isModal

这比让视图事后发现其状态要好吗?


它知道它正在呈现一个UITabBarController,但它不知道它正在呈现子类化的UITableViewController(由UITabBarController呈现的许多中间UINavigationController之一呈现),实际上需要知道它是否以模态方式呈现。这种方法难道不需要我对所有其他股票中间视图控制器进行子类化,以确保isModal值到达必要的视图吗? - Shaun Inman

1

在这个 Swift 时代,有一种更简单的方法。

extension UIViewController {

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

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接