Comment puis-je, dans mon code de contrôleur de vue, différencier entre:
presentingViewController
et isMovingToParentViewController
sont YES
dans les deux cas, ils ne sont donc pas très utiles.
Ce qui complique les choses, c’est que mon contrôleur de vue parent est parfois modal, sur lequel le contrôleur de vue à vérifier est poussé.
Il se trouve que mon problème est d’incorporer ma HtmlViewController
dans une UINavigationController
qui est ensuite présentée. C'est pourquoi mes propres tentatives et les bonnes réponses ci-dessous ne fonctionnaient pas.
HtmlViewController* termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;
modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
animated:YES
completion:nil];
Je suppose que je ferais mieux de dire à mon contrôleur de vue quand il est modal, au lieu d'essayer de déterminer.
Prendre avec un grain de sel, n'a pas 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;
}
Vous avez négligé une méthode: isBeingPresented
.
isBeingPresented
est vrai lorsque le contrôleur de vue est présenté et faux lorsqu'il est poussé.
- (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
}
}
Dans 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
}
}
self.navigationController! = nil voudrait dire que c'est dans une navigation empiler.
Afin de gérer le cas où le contrôleur de vue actuel est poussé alors que le contrôleur de navigation est présenté sous forme modale, j'ai ajouté quelques lignes de code pour vérifier si le contrôleur de vue actuel est le contrôleur racine dans la pile de navigation.
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
Voici une solution qui résout le problème mentionné dans les réponses précédentes, lorsque isModal()
renvoie true
si poussé UIViewController
se trouve dans une pile UINavigationController
présentée.
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
}
}
}
Cela fonctionne pour moi jusqu'à présent ... Si quelques optimisations, merci de les partager.
Swift 4
var isModal: Bool {
return presentingViewController != nil ||
navigationController?.presentingViewController?.presentedViewController === navigationController ||
tabBarController?.presentingViewController is UITabBarController
}
Comme beaucoup de gens le suggèrent ici, les méthodes de "vérification" ne fonctionnent pas bien dans tous les cas, dans mon projet, j'ai trouvé une solution permettant de gérer cela manuellement .. Ce n'est pas ce qui se passe en coulisses et il faut l'introspection.
DEViewController.h
fichier:
#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
Les présentations peuvent maintenant être gérées de la manière suivante:
poussé sur la pile de navigation:
// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];
présenté modalement avec navigation:
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];
présenté sous forme modale:
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];
De plus, dans DEViewController
, nous pourrions ajouter un repli à "vérifier" si la propriété susmentionnée est égale à 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;
}
}
En supposant que tous les viewControllers que vous présentez de manière modale soient enveloppés dans un nouveau navigationController (ce que vous devriez toujours faire de toute façon), vous pouvez ajouter cette propriété à votre VC.
private var wasPushed: Bool {
guard let vc = navigationController?.viewControllers.first where vc == self else {
return true
}
return false
}
self.navigationController != nil
voudrait dire que c'est dans une pile de navigation.
Pour détecter votre contrôleur est poussé ou pas simplement utiliser le code ci-dessous dans n'importe où vous voulez:
if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {
// Not pushed
}
else {
// Pushed
}
J'espère que ce code peut aider n'importe qui ...
if navigationController.presentingViewController != nil {
// Navigation controller is being presented modally
}
Si vous utilisez ios 5.0 ou une version ultérieure, veuillez utiliser ce 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;
}
}
if let navigationController = self.navigationController, navigationController.isBeingPresented {
// being presented
}else{
// being pushed
}