提问人:meaning-matters 提问时间:5/13/2014 最后编辑:craftmeaning-matters 更新时间:3/17/2022 访问量:159485
如何检查视图控制器是以模式方式呈现还是在导航堆栈上推送?
How to check if a view controller is presented modally or pushed on a navigation stack?
问:
如何在视图控制器代码中区分:
- 以模式呈现
- 推送导航堆栈
在这两种情况下都是,所以不是很有帮助。presentingViewController
isMovingToParentViewController
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];
我想我最好告诉我的视图控制器何时是模态的,而不是试图确定。
答:
self.navigationController != nil
这意味着它位于导航堆栈中。
评论
用一粒盐服用,没有测试。
- (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;
}
评论
presentingViewController
当被设置为根时,返回推送的 VC。所以,不适合我的情况。YES
UITabBarController
您忽略了一种方法:.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
}
}
评论
isBeingPresented
NO
UINavigationController
isBeingPresented
UINavigationController
isBeingPresented
isBeingDismissed
isMovingFromParentViewController
isMovingToParentViewController
view[Will|Did][Disa|A]ppear
在 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
}
}
评论
id presentedController = self.navigationController.modalViewController;
if (presentedController) {
// Some view is Presented
} else {
// Some view is Pushed
}
这将使您知道 viewController 是否显示或推送
评论
正如这里的许多人所建议的那样,“检查”方法并不适用于所有情况,在我的项目中,我提出了手动管理的解决方案。 关键是,我们通常自己管理演示 - 这不是幕后发生的事情,我们必须反省。
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
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;
}
}
self.navigationController != nil 表示它在导航中 叠。
为了处理导航控制器以模式呈现时推送当前视图控制器的情况,我添加了一些代码行来检查当前视图控制器是否是导航堆栈中的根控制器。
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 let navigationController = navigationController, navigationController.presentingViewController?.presentedViewController == navigationController {
return true
} else if let tabBarController = tabBarController, tabBarController.presentingViewController is UITabBarController {
return true
} else {
return false
}
}
}
评论
假设您以模式方式呈现的所有 viewController 都包装在一个新的 navigationController 中(无论如何您都应该这样做),您可以将此属性添加到您的 VC 中。
private var wasPushed: Bool {
guard let vc = navigationController?.viewControllers.first where vc == self else {
return true
}
return false
}
评论
对于一些想知道的人,如何告诉 ViewController 它正在呈现
如果正在演示/推送A
B
定义一个 和 in
enum
property
B
enum ViewPresentationStyle { case Push case Present } //and write property var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed
现在在视图控制器中,通过分配来判断它是否正在呈现/推送
A
B
presentationStyle
func presentBViewController() { let bViewController = B() bViewController.vcPresentationStyle = .Present //telling B that it is being presented self.presentViewController(bViewController, animated: true, completion: nil) }
在视图控制器中的使用
B
override func viewDidLoad() { super.viewDidLoad() if self.vcPresentationStyle == .Present { //is being presented } else { //is being pushed } }
Swift 5
这是一个解决方案,它解决了前面答案中提到的问题,当推送的返回在呈现的堆栈中时。isModal()
true
UIViewController
UINavigationController
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
}
}
}
到目前为止,它确实对我有用。 如果有一些优化,请分享。
评论
tabBarController?.presentingViewController is UITabBarController
presentingViewController
isModal
true
如果您使用的是 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 {
return presentingViewController != nil ||
navigationController?.presentingViewController?.presentedViewController === navigationController ||
tabBarController?.presentingViewController is UITabBarController
}
评论
要检测您的控制器是否被推送,只需在您想要的任何位置使用以下代码:
if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {
// Not pushed
}
else {
// Pushed
}
我希望这段代码可以帮助任何人......
评论
if let navigationController = self.navigationController, navigationController.isBeingPresented {
// being presented
}else{
// being pushed
}
斯威夫特 5.干净简单。
if navigationController?.presentingViewController != nil {
// Navigation controller is being presented modally
}
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 的回答。同样,还有更多优化的空间。请在评论部分讨论需要处理的案例。
评论
这个解决方案 - 在 iOS 15 和 Xcode 13.1 下测试:
var isPresented: Bool {
if let nvc = navigationController {
return nvc.viewControllers.firstIndex(of: self) == 0
} else {
return presentingViewController != nil
}
}
评论