检查视图控制器是以模态方式呈现,还是推送到导航堆栈上

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

  • 以模态方式呈现
  • 推在导航堆栈上

在这两种情况下presentingViewController isMovingToParentViewControllerisMovingToParentViewController都是YES ,所以不是很有帮助。

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

事实certificate,我的问题是,我embedded我的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]; 

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

12 Solutions collect form web for “检查视图控制器是以模态方式呈现,还是推送到导航堆栈上”

拿一粒盐,没有testing。

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

你忽略了一个方法: isBeingPresented

当呈现视图控制器时isBeingPresented是正确的,被推入时是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 } } 

Swift中

 func isModal() -> Bool { if self.presentingViewController != nil { return true } else if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController { return true } else if self.tabBarController?.presentingViewController is UITabBarController { return true } return false } 

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

Swift 3
这里是解决前面提到的问题的解决scheme,当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 } } } 

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

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

许多人在这里build议,“检查”方法不适用于所有情况下,在我的项目中,我已经提出了解决scheme来手动pipe理。 关键是,我们通常自己pipe理演示 – 这不是幕后发生的事情,我们必须反思。

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 

现在的演讲可以这样pipe理:

按导航堆栈:

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

以导航的forms呈现:

 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 ,如果上述属性等于DEViewController我们可以添加一个回退“检查”:

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

假设你模式化的所有viewController被包装在一个新的导航控制器(你总是应该这样做),你可以添加这个属性到你的VC。

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

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

}

斯威夫特4

 var isModal: Bool { if presentingViewController != nil { return true } if navigationController?.presentingViewController?.presentedViewController == navigationController { return true } if let presentingVC = tabBarController?.presentingViewController, presentingVC is UITabBarController { return true } return false } 
 id presentedController = self.navigationController.modalViewController; if (presentedController) { // Some view is Presented } else { // Some view is Pushed } 

这将让你知道如果viewController呈现或推

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

如果A正在呈现/推动B

  1. B定义一个enumproperty

     enum ViewPresentationStyle { case Push case Present } //and write property var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
  2. 现在在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) } 
  3. B视图控制器中的用法

     override func viewDidLoad() { super.viewDidLoad() if self.vcPresentationStyle == .Present { //is being presented } else { //is being pushed } } 
  • UIViewController返回无效的框架?
  • 如何只允许单个UIViewController在风景和肖像方向旋转?
  • 在iOS8中使用Swift更改特定ViewController的状态栏颜色
  • iPhone - closures多个ViewControllers
  • 如何在Swift中设置状态栏风格3
  • 如何在Swift中为UIViewController子类创build自定义初始化程序?
  • 从应用程序委托使用swift打开视图控制器
  • 无法识别的select器发送到实例
  • 拒绝提出的视图控制器
  • 我可以使用自动布局为横向和纵向提供不同的约束吗?
  • 为什么在我的UIViewController的顶部20px的差距?