简体   繁体   English

如何识别出呈现UIViewController

[英]How to identify that an UIViewController is presented

I have created an UIViewController sub class which can either be pushed in a navigation stack of a UINavigationController or presented(modally) from any UIViewController. 我创建了一个UIViewController子类,它可以在UINavigationController的导航堆栈中推送,也可以从任何UIViewController呈现(模态)。 I need to identify whether my view controller is presented, if it is presented I need to add a toolbar with a close button at the top of the view controller. 我需要确定是否显示了我的视图控制器,如果显示,我需要在视图控制器的顶部添加一个带有关闭按钮的工具栏。 (else if it is pushed in navigation stack then the default close button will get added, by using that the user can go back.) (否则,如果将其推入导航堆栈,则会添加默认关闭按钮,使用该用户可以返回。)

In all the available versions say 4.3, 5.0, till 6.0, from inside an UIViewController sub class, Can I assume that the view controller is presented(modally) if the following condition is satisfied. 在UIViewController子类内部的所有可用版本中说4.3,5.0,直到6.0,如果满足以下条件,我可以假设视图控制器是以模态方式呈现的。

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

With iOS 5, UIViewController gained a readonly property named presentingViewController , that replaces the older semantics of parentViewController (which now describes containment ). 与iOS 5,获得的UIViewController命名一个只读属性presentingViewController ,替换较旧的语义parentViewController (现在描述遏制 )。 This property can be used when a view controller needs to get at the view controller that's presenting it — note: this will often be something else than what you'd expect, if you're new to the API! 当视图控制器需要访问呈现它的视图控制器时,可以使用此属性 - 注意:如果您是API新手,这通常会超出您的期望!

In addition, the isBeingPresented property had been introduced to pretty much solve the class of situations you're currently in. Check for this property in your view controller's viewWillAppear: . 此外,引入isBeingPresented属性几乎可以解决您当前所处的情况。在视图控制器的viewWillAppear:检查此属性viewWillAppear:

Update 更新

I overread that you seem to target iOS 4.3 as well: 我认为你似乎也瞄准了iOS 4.3:
In that case, you need to guard the call to isBeingPresented with an if ([self respondsToSelector:…]) you can then in the else block check for whether the parentViewController is not nil. 在这种情况下,你需要使用if ([self respondsToSelector:…])来保护对isBeingPresented的调用,然后你可以在else块中检查parentViewController是否不是nil。

Another approach to backwards compatibility might be to override +resolveInstanceMethod: to add an implementation for -isBeingPresented at runtime. 另一种向后兼容的方法可能是覆盖+resolveInstanceMethod:在运行时为-isBeingPresented添加实现。 This will leave your calling sites clean, and you'd get rid of runtime-magic as soon as you let go of ancient iOS support ;-) 这将使您的呼叫站点保持干净,只要您放弃古老的iOS支持,您就可以摆脱运行时魔术;-)

Note, though, that there are edge cases to this, and you initial approach as well, when running on iOS <5: 但是请注意,有这样的边缘情况,并且在iOS <5上运行时也是初始方法:

The view controller can be presented contained in any other view controller—including navigation controllers. 视图控制器可以包含在任何其他视图控制器中,包括导航控制器。 When that last case happens, you're out of luck: parentViewController will be nil , while navigationController will not . 当最后一种情况发生时,你运气不好: parentViewController将为nil ,而navigationController不会 You can try to add gobs of unwieldy code to mitigate this limitation in older iOSes…or you could just let it go. 您可以尝试添加大量笨拙的代码来缓解旧iOS中的这种限制......或者您可以放手。

I use the this code to check whether the UIViewController is presented. 我使用此代码来检查是否显示了UIViewController。

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

I had a similar case, however the view controller that I presented is wrapped in it's own navigation controller . 我有一个类似的情况,但我提出的视图控制器包含在它自己的导航控制器中 So in that view controller when I need to determine whether or not to add the close button vs a back button, I just check the navigation controllers stack size . 因此在该视图控制器中,当我需要确定是否添加关闭按钮与后退按钮时, 我只需检查导航控制器堆栈大小 If the screen is presented, the stack size should be one (needs close button)... and if it is pushed using an existing navigation controller, then stack size will be larger than one (needs back button). 如果显示屏幕,则堆栈大小应为1(需要关闭按钮)...如果使用现有导航控制器推送,则堆栈大小将大于1(需要后退按钮)。

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

To handle this kind of behavior, I usually set/reset a BOOL toggling it in viewWillAppear/viewWillDisappear methods. 为了处理这种行为,我通常在viewWillAppear / viewWillDisappear方法中设置/重置BOOL切换它。

By the way, your test condition seems incorrect. 顺便说一下,你的测试条件似乎不正确。 I think you should use 我想你应该用

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

Why can't you just always add the toolbar to your view controller? 为什么不能一直将工具栏添加到视图控制器? Is there any case the view is loaded but never presented? 是否有任何情况下加载视图但从未出现?

@saikamesh. @saikamesh。

As you use UINavigationController to navigate your viewControllers, I think you can use topViewController ( Doc here ) and visibleViewController ( Doc again ) to reach your intention. 当您使用UINavigationController导航viewControllers时,我认为您可以使用topViewController此处为Doc )和visibleViewController再次使用Doc )来达到您的意图。

You mention that : 你提到:

when it is pushed in navigation stack then the default close button will get added, by using that the user can go back 当它被推入导航堆栈时,将添加默认关闭按钮,使用该用户可以返回

If the instance of the the specific UIViewController is important, I think it better to create a shared singleton instance and provide a global presented flag: 如果特定UIViewController的实例很重要,我认为最好创建一个共享单例实例并提供一个全局呈现标志:

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

and to check if it is presented: 并检查是否出现:

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

Or, you can read the much accepted answer . 或者,您可以阅读广为接受的答案

:) Hope helps. :)希望有所帮助。

Please check this way: 请检查这种方式:

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

    }
}

You could do it like this, it's fast and safe 你可以这样做,它快速而安全

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
}

You can at any point check whether you have a modal view controller presented or not by using the modalViewController property from your navigation controller. 您可以通过使用导航控制器中的modalViewController属性随时检查是否有模态视图控制器。 Ex: 例如:

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

One elegant answer that I haven't seen here: 我没有在这里看到一个优雅的答案:

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

credit: based on this gist 信用:基于这个要点

In Swift on iOS 9 (or later): 在iOS 9(或更高版本)的Swift中:

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

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

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

Small modification in @AmitaiB answer to create a function, @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
    }

Just check by calling: 只需致电:

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

As Martin Reed said, this is the best way 正如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];
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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