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

时间:2014-05-12 22:58:01

标签: ios objective-c swift uiviewcontroller uinavigationcontroller

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

  • 以模态呈现
  • 推送导航堆栈

在这两种情况下,presentingViewControllerisMovingToParentViewController都是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];

我想我最好告诉我的视图控制器什么时候模态,而不是试图确定。

16 个答案:

答案 0 :(得分:113)

带上一粒盐,没有进行测试。

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

答案 1 :(得分:68)

您忽略了一种方法: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
    }
}

答案 2 :(得分:64)

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

答案 3 :(得分:20)

  

self.navigationController!= nil意味着它在导航中   叠加。

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

MySQL

答案 4 :(得分:17)

斯威夫特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
        }
    }
}

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

答案 5 :(得分:12)

Swift 4

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

答案 6 :(得分: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

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

推送到导航堆栈:

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

以模式显示导航:

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

以模态方式呈现:

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

另外,在DEViewController中,我们可以添加一个回退到&#34;检查&#34;如果上述属性等于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;
    }
}

答案 7 :(得分:3)

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

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

    return false
}

答案 8 :(得分:2)

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

答案 9 :(得分:2)

迅速5。简洁。

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

答案 10 :(得分:2)

Swift 5
这个方便的扩展程序处理的案例比以前的答案少得多。这些情况是VC(视图控制器)是应用程序窗口的根VC,VC作为子VC添加到父VC。仅当视图控制器以模态显示时,它才会尝试返回true。

extension UIViewController {
    /**
      returns true only if the viewcontroller is presented.
    */
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            if let parent = parent, !(parent is UINavigationController || parent is UITabBarController) {
                return false
            }
            return true
        } else if let navController = navigationController, navController.presentingViewController?.presentedViewController == navController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        }
        return false
    }
}

感谢Jonauz's answer。同样,还有进行更多优化的空间。请在注释部分中讨论需要处理的情况。

答案 11 :(得分:1)

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

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

    // Not pushed
}
else {

    // Pushed
}

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

答案 12 :(得分:0)

如果您使用的是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;
}

}

答案 13 :(得分:0)

if let navigationController = self.navigationController, navigationController.isBeingPresented {
    // being presented
}else{
    // being pushed
}

答案 14 :(得分:-1)

id presentedController = self.navigationController.modalViewController;
if (presentedController) {
     // Some view is Presented
} else {
     // Some view is Pushed
}

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

答案 15 :(得分:-1)

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

如果adb devices正在展示/推送A

  1. B

    中定义enumproperty
    B
  2. 现在在enum ViewPresentationStyle { case Push case Present } //and write property var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 视图控制器中,通过分配A

    告诉B是否正在显示/推送它
    presentationStyle
  3. func presentBViewController() { let bViewController = B() bViewController.vcPresentationStyle = .Present //telling B that it is being presented self.presentViewController(bViewController, animated: true, completion: nil) } 视图控制器

    中的用法
    B