【问题标题】:How to identify that an UIViewController is presented如何识别呈现了 UIViewController
【发布时间】:2013-02-12 00:20:42
【问题描述】:

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

在所有可用版本中,从 UIViewController 子类中的 4.3、5.0 到 6.0,如果满足以下条件,我是否可以假设视图控制器已呈现(模态)。

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

【问题讨论】:

标签: iphone ios objective-c uiviewcontroller modalviewcontroller


【解决方案1】:

正如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];
        }

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      @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 
      }
      

      【讨论】:

        【解决方案4】:

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

        // 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

        【讨论】:

          【解决方案5】:

          你可以这样,又快又安全

          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
          }
          

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

              我使用这段代码来检查 UIViewController 是否出现。

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

              【讨论】:

              • 如果你正在检查你的根视图控制器,这将永远为零。对于根控制器,我检查 self.presentedViewController == nil。如果它不是 nil,则表示它正在呈现其他内容,并且根不再可见。
              【解决方案8】:

              在 iOS 5 中,UIViewController 获得了一个名为 presentingViewController 的只读属性,它取代了旧的 parentViewController 语义(现在描述了 containment)。当视图控制器需要访问呈现它的视图控制器时,可以使用此属性 - 注意:如果您是 API 新手,这通常会与您期望的不同!

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

              更新

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

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

              但请注意,在 iOS

              视图控制器可以包含在任何其他视图控制器中——包括导航控制器。当最后一种情况发生时,你就不走运了:parentViewController 将是 nil,而 navigationController不是。您可以尝试添加大量笨拙的代码来缓解旧 iOS 中的这种限制……或者您可以放弃它。

              【讨论】:

              • isBeingPresented 正是我需要检查是否确定我的视图控制器是否在 iOS 5.0 及更高版本中呈现或推送。但是要支持 4.3,我不能只检查 parentViewController 不为零,对吗?因为 parentViewController 不是 nil,所以在两种情况下都推送和呈现。 parentViewController 文档说“在 iOS 5.0 之前,如果视图没有父视图控制器并且正在呈现,则将返回呈现视图控制器。”我也理解在运行时添加实现。可以详细说明吗?
              • 在 iOS parentViewController 的意思是“呈现给你的视图控制器”。 IIRC,排除收容。您可能不想在运行时添加实现,但如果您真的感兴趣,请查看 +resolveInstanceMethod:the guide 的文档。
              【解决方案9】:

              @saikamesh。

              当你使用 UINavigationController 来导航你的 viewControllers 时,我认为你可以使用 topViewController (Doc here) 和 visibleViewController (Doc 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

              :) 希望有所帮助。

              【讨论】:

              • 突然间你需要两个实例,但你搞砸了,因为你让汉兰达输了。斩首无助的视图控制器,惊呼“只能有一个!”
              【解决方案10】:

              您可以随时使用导航控制器中的 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
                    }
                 }
              

              【讨论】:

                【解决方案11】:

                请这样检查:

                 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");
                        }
                
                    }
                }
                

                【讨论】:

                  【解决方案12】:

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

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

                  【讨论】:

                    【解决方案13】:

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

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

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

                    为什么不能总是将工具栏添加到视图控制器?是否存在视图已加载但从未呈现的情况?

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2013-10-26
                      • 2015-12-02
                      相关资源
                      最近更新 更多