首页 文章

检查视图控制器是以模态方式呈现还是在推理堆栈上推送

提问于
浏览
86

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

  • 以模态呈现

  • 推送到导航堆栈

在这两种情况下, presentingViewController 和_1449239都都是 YES ,因此不是很有用 .

令我感到困惑的是,我的父视图控制器有时是模态的,在其上推送要检查的视图控制器 .

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

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

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

我想我最好告诉我的视图控制器何时是模态,而不是试图确定 .

14 回答

  • 3

    Swift 4

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

    self.navigationController != nil 意味着它在导航堆栈中 .

  • 110

    拿一粒盐,没试过 .

    - (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;
     }
    
  • 62

    你忽略了一种方法: isBeingPresented .

    isBeingPresented 在呈现视图控制器时为true,在被推送时为false .

    - (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
        }
    }
    
  • 1

    Swift

    // 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 || false
        }
    }
    
  • 3

    self.navigationController!= nil意味着它在导航堆栈中 .

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

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

    Swift 3
    这是解决前面答案中提到的问题的解决方案,当 isModal() 返回 true 时,如果推送 UIViewController 在呈现的 UINavigationController 堆栈中 .

    extension UIViewController {
        var isModal: Bool {
            if let index = navigationController?.viewControllers.index(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
            }
        }
    }
    

    到目前为止它对我有用 . 如果进行一些优化,请分享 .

  • 3

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

    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
    

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

    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];
    

    另外,在 DEViewController 中,如果上述属性等于 SSViewControllerPresentationMethodUnspecified ,我们可以添加回退到"checking":

    - (BOOL)isViewControllerPushed
    {
        if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
            return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
        }
    
        else {
            // fallback to default determination method
            return (BOOL)self.navigationController.viewControllers.count > 1;
        }
    }
    
  • -1

    假设您以模态方式呈现的所有viewControllers都包含在一个新的navigationController中(您应该始终这样做),您可以将此属性添加到VC中 .

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

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

    if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {
    
        // Not pushed
    }
    else {
    
        // Pushed
    }
    

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

  • -1

    如果您使用的是ios 5.0或更高版本,请使用此代码

    -(BOOL)isPresented
    {
    if ([self isBeingPresented]) {
        // being presented
         return YES;
    } else if ([self isMovingToParentViewController]) {
        // being pushed
         return NO;
    } else {
        // simply showing again because another VC was dismissed
         return NO;
    }
    

    }

  • 0
    if let navigationController = self.navigationController, navigationController.isBeingPresented {
        // being presented
    }else{
        // being pushed
    }
    
  • 11
    id presentedController = self.navigationController.modalViewController;
    if (presentedController) {
         // Some view is Presented
    } else {
         // Some view is Pushed
    }
    

    这将告诉您是否呈现或推送了viewController

  • 0

    对于一些想知道的人,如何告诉ViewController它正在呈现

    如果 A 正在展示/推动 B

    • B 中定义 enumproperty
    enum ViewPresentationStyle {
        case Push
        case Present
    }
    
    //and write property 
    
    var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed
    
    • 现在在 A 视图控制器中,通过分配 presentationStyle 告诉 B 是否正在显示/推送它
    func presentBViewController() {
        let bViewController = B()
        bViewController.vcPresentationStyle = .Present //telling B that it is being presented
        self.presentViewController(bViewController, animated: true, completion: nil)
    }
    
    • B View Controller中的用法
    override func viewDidLoad() {
        super.viewDidLoad()
    
        if self.vcPresentationStyle == .Present {
            //is being presented 
        }
        else {
            //is being pushed
        }
    
    }
    

相关问题