ios 如何检查视图控制器是模态呈现还是推送到导航堆栈上?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23620276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:07:38  来源:igfitidea点击:

How to check if a view controller is presented modally or pushed on a navigation stack?

iosobjective-cswiftuiviewcontrolleruinavigationcontroller

提问by meaning-matters

How can I, in my view controller code, differentiate between:

在我的视图控制器代码中,我如何区分:

  • presented modally
  • pushed on navigation stack
  • 模态地呈现
  • 推送到导航堆栈上

Both presentingViewControllerand isMovingToParentViewControllerare YESin both cases, so are not very helpful.

这两个presentingViewControllerisMovingToParentViewControllerYES在这两种情况下,所以都不是很有益的。

What complicates things is that my parent view controller is sometimes modal, on which the to be checked view controller is pushed.

使事情复杂化的是我的父视图控制器有时是模态的,要检查的视图控制器被推送到模态。

It turns out my issue is that I embed my HtmlViewControllerin a UINavigationControllerwhich is then presented. That's why my own attempts and the good answers below were not working.

事实证明,我的问题是我将我的嵌入HtmlViewController到 a 中UINavigationController,然后呈现出来。这就是为什么我自己的尝试和下面的好答案不起作用的原因。

HtmlViewController*     termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;

modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
                   animated:YES
                 completion:nil];

I guess I'd better tell my view controller when it's modal, instead of trying to determine.

我想我最好在它处于模态时告诉我的视图控制器,而不是试图确定。

回答by ColdLogic

Take with a grain of salt, didn't test.

拿一点盐,没有测试。

- (BOOL)isModal {
     if([self presentingViewController])
         return YES;
     if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
         return YES;
     if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
         return YES;

    return NO;
 }

回答by King-Wizard

In Swift:

斯威夫特

Add a flag to test if it's a modal by the class type:

添加一个标志来测试它是否是类类型的模态:

// MARK: - UIViewController implementation

extension UIViewController {

    var isModal: Bool {

        let presentingIsModal = presentingViewController != nil
        let presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController
        let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController

        return presentingIsModal || presentingIsNavigation || presentingIsTabBar
    }
}

回答by rmaddy

You overlooked one method: isBeingPresented.

您忽略了一种方法:isBeingPresented.

isBeingPresentedis true when the view controller is being presented and false when being pushed.

isBeingPresented呈现视图控制器时为真,推送时为假。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if ([self isBeingPresented]) {
        // being presented
    } else if ([self isMovingToParentViewController]) {
        // being pushed
    } else {
        // simply showing again because another VC was dismissed
    }
}

回答by Jonauz

Swift 5
Here is solution that addresses the issue mentioned with previous answers, when isModal()returns trueif pushed UIViewControlleris in a presented UINavigationControllerstack.

Swift 5
Here 是解决先前答案中提到的问题的解决方案,当推送在呈现的堆栈中时isModal()返回。trueUIViewControllerUINavigationController

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if navigationController?.presentingViewController?.presentedViewController == navigationController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

It does work for me so far. If some optimizations, please share.

到目前为止,它确实对我有用。如果有一些优化,请分享。

回答by Jibeex

self.navigationController != nil would mean it's in a navigation stack.

self.navigationController != nil 表示它在导航堆栈中。

In order to handle the case that the current view controller is pushed while the navigation controller is presented modally, I have added some lines of code to check if the current view controller is the root controller in the navigation stack .

为了处理在导航控制器以模态呈现的同时推送当前视图控制器的情况,我添加了一些代码行来检查当前视图控制器是否是导航堆栈中的根控制器。

extension UIViewController{
func isModal() -> Bool {

    if let navigationController = self.navigationController{
        if navigationController.viewControllers.first != self{
            return false
        }
    }

    if self.presentingViewController != nil {
        return true
    }

    if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController  {
        return true
    }

    if self.tabBarController?.presentingViewController is UITabBarController {
        return true
    }

    return false
   }
}

回答by Charlton Provatas

Swift 4

斯威夫特 4

var isModal: Bool {
    return presentingViewController != nil ||
           navigationController?.presentingViewController?.presentedViewController === navigationController ||
           tabBarController?.presentingViewController is UITabBarController
}

回答by Kirill Kudaev

Swift 5.Clean and simple.

Swift 5.干净简单。

if navigationController.presentingViewController != nil {
    // Navigation controller is being presented modally
}

回答by Yevhen Dubinin

As many folks here suggest, that "checking" methods don't work well for all cases, in my project I've come up with solution to manage that manually. The point is, we usually manage presentation on our own - this is not what happens behind the scene and we must to introspect.

正如这里的许多人所建议的那样,“检查”方法并不适用于所有情况,在我的项目中,我提出了手动管理的解决方案。关键是,我们通常自己管理演示文稿——这不是幕后发生的事情,我们必须反省。

DEViewController.hfile:

DEViewController.h文件:

#import <UIKit/UIKit.h>

// it is a base class for all view controllers within a project
@interface DEViewController : UIViewController 

// specify a way viewcontroller, is presented  by another viewcontroller
// the presented view controller should manually assign the value to it
typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) {
    SSViewControllerPresentationMethodUnspecified = 0,
    SSViewControllerPresentationMethodPush,
    SSViewControllerPresentationMethodModal,
};
@property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod;

// other properties/methods...
@end

The presentations now could be managed this way:

现在可以通过以下方式管理演示文稿:

pushed on navigation stack:

推送到导航堆栈上:

// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];

presented modally with navigation:

以导航方式呈现:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
                               initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];

presented modally:

模态呈现:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];

Also, in DEViewControllerwe could add a fallback to "checking" if the aforementioned property equals to SSViewControllerPresentationMethodUnspecified:

此外,DEViewController如果上述属性等于SSViewControllerPresentationMethodUnspecified

- (BOOL)isViewControllerPushed
{
    if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
        return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
    }

    else {
        // fallback to default determination method
        return (BOOL)self.navigationController.viewControllers.count > 1;
    }
}

回答by Demosthese

Assuming that all viewControllers that you present modally are wrapped inside a new navigationController (which you should always do anyway), you can add this property to your VC.

假设您以模态方式呈现的所有 viewController 都包含在一个新的 navigationController 中(无论如何您都应该这样做),您可以将此属性添加到您的 VC 中。

private var wasPushed: Bool {
    guard let vc = navigationController?.viewControllers.first where vc == self else {
        return true
    }

    return false
}

回答by Arash Zeinoddini

To detect your controller is pushed or not just use below code in anywhere you want:

要检测您的控制器是否被推送,只需在您想要的任何地方使用以下代码:

if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {

    // Not pushed
}
else {

    // Pushed
}

I hope this code can help anyone...

我希望这段代码可以帮助任何人...