如何识别出呈现UIViewController

时间:2013-02-26 13:58:27

标签: iphone ios objective-c uiviewcontroller modalviewcontroller

我创建了一个UIViewController子类,它可以在UINavigationController的导航堆栈中推送,也可以从任何UIViewController呈现(模态)。我需要确定是否显示了我的视图控制器,如果显示,我需要在视图控制器的顶部添加一个带有关闭按钮的工具栏。 (否则,如果将其推入导航堆栈,则会添加默认关闭按钮,使用该用户可以返回。)

在UIViewController子类内部的所有可用版本中说4.3,5.0,直到6.0,如果满足以下条件,我可以假设视图控制器是以模态方式呈现的。

if(self.parentViewController == nil || self.navigationController == nil)

13 个答案:

答案 0 :(得分:33)

使用iOS 5,UIViewController获得了一个名为presentingViewController的只读属性,它替换了parentViewController的旧语义(现在描述了包含)。当视图控制器需要访问呈现它的视图控制器时,可以使用此属性 - 注意:如果您不熟悉API,这通常会超出您的期望!

此外,引入了isBeingPresented属性几乎可以解决您当前所处的情况。在视图控制器的viewWillAppear:中检查此属性。

更新

我认为你似乎也瞄准了iOS 4.3:
在这种情况下,您需要使用isBeingPresented保护对if ([self respondsToSelector:…])的调用,然后您可以在else块中检查parentViewController是否为零。

向后兼容性的另一种方法可能是覆盖+resolveInstanceMethod:以在运行时为-isBeingPresented添加实现。这将使您的呼叫站点保持干净,并且只要您放弃古老的iOS支持,就可以摆脱运行时魔术; - )

但是请注意,在iOS< 5:

上运行时,有一些边缘情况,以及初始方法

视图控制器可以包含在任何其他视图控制器中 - 包括导航控制器。当最后一种情况发生时,您运气不好:parentViewController将为nil,而navigationController。您可以尝试添加大量难以操作的代码来缓解旧iOS中的这种限制......或者您可以放手。

答案 1 :(得分:10)

我使用此代码检查是否显示了UIViewController。

if (uiviewcontroller.presentingViewController != nil) {
   // do something
}

答案 2 :(得分:7)

为了处理这种行为,我通常在viewWillAppear / viewWillDisappear方法中设置/重置BOOL切换它。

顺便说一句,您的测试条件似乎不正确。我认为你应该使用

if(self.parentViewController != nil || self.navigationController != nil)

为什么不能一直将工具栏添加到视图控制器中?是否有任何情况下视图已加载但从未显示过?

答案 3 :(得分:7)

我有一个类似的情况,但我提供的视图控制器包装在它自己的导航控制器中。所以在该视图控制器中,当我需要确定是否添加关闭按钮与后退按钮时,我只检查导航控制器堆栈大小。如果显示屏幕,则堆栈大小应为1(需要关闭按钮)...如果使用现有导航控制器推送,则堆栈大小将大于1(需要后退按钮)。

BOOL presented = [[self.navigationController viewControllers] count] == 1;

答案 4 :(得分:3)

@saikamesh。

当您使用UINavigationController导航viewControllers时,我认为您可以使用topViewControllerDoc here)和visibleViewControllerDoc again)来达到您的意图。

你提到:

  

当它被推入导航堆栈时,则默认关闭按钮   将添加,使用该用户可以返回

如果特定UIViewController的实例很重要,我认为最好创建一个共享单例实例并提供一个全局呈现标志:

id specificVC = [SpecificViewController sharedInstance];
if (specificVC.isPushed) {
    [self.navController popToViewController:specificVC animated:YES];
}

并检查是否出现:

if ([self.navController.visibleViewController isKindOfClass:[SpecificViewController class]]) {
    // Hide or add close button
    self.isPresented = YES;
}

或者,您可以阅读the much accepted answer

:)希望有所帮助。

答案 5 :(得分:2)

请检查这个方式:

 for (UIViewController*vc in [self.navigationController viewControllers]) {
    if ([vc isKindOfClass: [OffersViewController class]]){ //this line also checks OffersViewController is presented or not 

        if(vc.isViewLoaded){
             NSLog(@"Yes");
        }

    }
}

答案 6 :(得分:2)

你可以这样做,它快速而安全

UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

// Find the top controller on the view hierarchy
while (topController.presentedViewController) {
    topController = topController.presentedViewController;
}

// If the top controller it is not already presented
if (![topController isKindOfClass:[YourViewController class]]) {
    // Present it
    [topController presentViewController:yourViewController animated:YES completion:nil];
}
else {
// do some stuff here
}

答案 7 :(得分:1)

您可以随时使用导航控制器中的modalViewController属性检查是否有模态视图控制器。 例如:

   UIViewController *presentedController = self.navigationController.modalViewController;
   if (presentedController) {
      // At this point, you have a view controller presented from your navigation controller
      if ([presentedController isKindOfClass:[controllerYouWantToCheck class]]) {
         // add your toolbar/buttons/etc here
      }
   }

答案 8 :(得分:1)

我在这里没有看到一个优雅的答案:

// Edit: Added 2 other modal cases
extension UIViewController {
    var isModal: Bool { 
        return self.presentingViewController?.presentedViewController == self
            || (navigationController != nil && navigationController?.presentingViewController?.presentedViewController == navigationController)
            || tabBarController?.presentingViewController is UITabBarController
    }
}

信用:基于this gist

答案 9 :(得分:1)

在iOS 9(或更高版本)上的Swift中:

if viewController.viewIfLoaded?.window != nil {
    // viewController is visible
}

答案 10 :(得分:0)

如果是我,我会有一个自定义初始化方法,并在创建vc时使用它。

vc = [[[MyUIViewControllerSubClass alloc] init] initWithToolbarAndCloseButton:YES];

答案 11 :(得分:0)

在@AmitaiB答案中进行小的修改以创建函数

func isModallyPresented(tmpVC:UIViewController) -> Bool {
        return tmpVC.presentingViewController?.presentedViewController == tmpVC
            || (tmpVC.navigationController != nil && tmpVC.navigationController?.presentingViewController?.presentedViewController == tmpVC.navigationController)
            || tmpVC.tabBarController?.presentingViewController is UITabBarController
    }

只需通过以下方式进行检查:

if(isModallyPresented(tmpVC:myTopVC)){
//return true if viewcontroller is presented 
}

答案 12 :(得分:0)

正如Martin Reed所说,这是最好的方法

            BOOL presented = [[self.navigationController viewControllers] count] == 1;
        if (presented) {
            [self dismissViewControllerAnimated:YES completion:^{
                // do whatever you need here
            }];
        }
        else {
            [self.navigationController popViewControllerAnimated:YES];
        }