可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How can I, in my view controller code, differentiate between:
- presented modally
- pushed on navigation stack
Both presentingViewController
and isMovingToParentViewController
are YES
in both cases, so are not very helpful.
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 HtmlViewController
in a UINavigationController
which is then presented. That's why my own attempts and the good answers below were not working.
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.
回答1:
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;
}
回答2:
You overlooked one method: isBeingPresented
.
isBeingPresented
is true when the view controller is being presented and false when being pushed.
- (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
}
}
回答3:
In 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
}
}
回答4:
self.navigationController != nil would mean it's in a navigation
stack.
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
}
}
回答5:
Swift 3
Here is solution that addresses the issue mentioned with previous answers, when isModal()
returns true
if pushed UIViewController
is in a presented UINavigationController
stack.
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
}
}
}
It does work for me so far.
If some optimizations, please share.
回答6:
Swift 4
var isModal: Bool {
return presentingViewController != nil ||
navigationController?.presentingViewController?.presentedViewController === navigationController ||
tabBarController?.presentingViewController is UITabBarController
}
回答7:
self.navigationController != nil
would mean it's in a navigation stack.
回答8:
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.h
file:
#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 DEViewController
we could add a fallback to "checking" if the aforementioned property equals to 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;
}
}
回答9:
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.
private var wasPushed: Bool {
guard let vc = navigationController?.viewControllers.first where vc == self else {
return true
}
return false
}
回答10:
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...
回答11:
If you are using ios 5.0 or later than please use this code
-(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;
}
}
回答12:
if let navigationController = self.navigationController, navigationController.isBeingPresented {
// being presented
}else{
// being pushed
}
回答13:
id presentedController = self.navigationController.modalViewController;
if (presentedController) {
// Some view is Presented
} else {
// Some view is Pushed
}
This will let you know if viewController is presented or pushed
回答14:
For some one who's wondering, How to tell ViewController that it is being presented
if A
is presenting/pushing B
Define an enum
and property
in B
enum ViewPresentationStyle {
case Push
case Present
}
//and write property
var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed
Now in A
view controller, tell B
if it is being presented/pushed by assigning presentationStyle
func presentBViewController() {
let bViewController = B()
bViewController.vcPresentationStyle = .Present //telling B that it is being presented
self.presentViewController(bViewController, animated: true, completion: nil)
}
Usage in B
View Controller
override func viewDidLoad() {
super.viewDidLoad()
if self.vcPresentationStyle == .Present {
//is being presented
}
else {
//is being pushed
}
}