Respostas:
Uma vez que se modalViewController
tornou obsoleto no iOS 6, aqui está uma versão que funciona para iOS 5+ e que compila sem avisos.
Objective-C:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
Rápido:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
Gorjeta de chapéu à resposta de Felipe.
nil == nil
retorna YES
, e não é o resultado que queremos.
Se você está procurando pelo iOS 6+, esta resposta está obsoleta e você deve verificar a resposta de Gabriele Petronella
Não há uma maneira legal de fazer isso, como uma propriedade ou método nativo do UIKit. O que você pode fazer é verificar vários aspectos do seu controlador para garantir que ele seja apresentado como modal.
Então, para verificar se o controlador atual (representado self
no código abaixo) é apresentado de forma modal ou não, tenho a função abaixo ou em uma UIViewController
categoria, ou (caso seu projeto não necessite de outros controladores UIKit, como UITableViewController
por exemplo) em um controlador de base do qual meus outros controladores herdam
-(BOOL)isModal {
BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) ||
//or if I have a navigation controller, check if its parent modal view controller is self navigation controller
( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) ||
//or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
[[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);
//iOS 5+
if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {
isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) ||
//or if I have a navigation controller, check if its parent modal view controller is self navigation controller
(self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) ||
//or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
[[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);
}
return isModal;
}
EDIT: Eu adicionei a última verificação para ver se um UITabBarController está sendo usado, e você apresenta outro UITabBarController como modal.
EDIT 2: adicionado cheque iOS 5+, onde UIViewController
não responde parentViewController
mais, mas presentingViewController
sim.
EDITAR 3: criei uma essência para isso, apenas no caso de https://gist.github.com/3174081
modalViewController
propriedade está obsoleta a partir do iOS 6. A documentação sugere o uso presentedViewController
.
NSLog(@"%@", self.navigationController.parentViewController)
impressões (null)
- você poderia explicar por quê? Meu ViewController está conectado ao controlador de visualização modal por meio do navController no storyboard.
.parentViewController
está obsoleto, .presentingViewController
deve ser usado em seu lugar.
No iOS5 +, como você pode ver em Referência de classe UIViewController , você pode obtê-lo na propriedade "presentationViewController".
PresentViewController O controlador de visualização que apresentou este controlador de visualização. (somente leitura)
@property (nonatomic, readonly) UIViewController * apresentandoViewController
Discussão
Se o controlador de exibição que recebeu esta mensagem for apresentado por outro controlador de exibição, esta propriedade mantém o controlador de exibição que o está apresentando. Se o controlador de visualização não for apresentado, mas um de seus ancestrais estiver sendo apresentado, esta propriedade mantém o controlador de visualização apresentando o ancestral mais próximo. Se nem o controlador de visualização nem qualquer um de seus ancestrais estiverem sendo apresentados, essa propriedade será nula.
Disponibilidade
Disponível no iOS 5.0 e posterior.
Declarado em
UIViewController.h
presentingViewController
. Ele também funcionará em controladores de visualização de contêiner, visto que atravessa automaticamente os ancestrais.
Se não houver, você pode definir uma propriedade para this ( presentedAsModal
) em sua subclasse UIViewController e configurá-la YES
antes de apresentar o ViewController como uma visualização modal.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Você pode verificar esse valor em sua viewWillAppear
substituição.
Acredito que não haja uma propriedade oficial que defina como a vista é apresentada, mas nada impede que você crie a sua própria.
UINavigationController
como modal ... a menos que você crie um controlador de navegação personalizado apenas para adicionar esta propriedade. E depois disso, dentro dos controladores, você terá que continuar lançando self.navigationController
para esta classe personalizada toda vez que precisar verificar se o controlador está apresentado como modal
A resposta de Petronella não funciona se self.navigationController for apresentado modalmente, mas self não for igual a self.navigationController.viewControllers [0], nesse caso self é pressionado.
Aqui está como você pode resolver o problema.
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
E em Swift:
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
|| self.tabBarController?.presentingViewController is UITabBarController
Isso deve funcionar.
if(self.parentViewController.modalViewController == self)…
UINavigationController
e UITabBarController
. Está funcionando muito bem até agora
Melhor maneira de verificar
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
Se você não precisa distinguir entre visualizações modais de tela cheia e visualizações não modais, que é o caso do meu projeto (eu estava lidando com um problema que ocorre apenas com folhas de formulário e folhas de página), você pode usar o método modalPresentationStyle propriedade de UIViewController:
switch (self.modalPresentationStyle) {
case 0: NSLog(@"full screen, or not modal"); break;
case 1: NSLog(@"page sheet"); break;
case 2: NSLog(@"form sheet"); break;
}
Em Swift :
func isUIViewControllerPresentedAsModal() -> Bool {
if((self.presentingViewController) != nil) {
return true
}
if(self.presentingViewController?.presentedViewController == self) {
return true
}
if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
return true
}
if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
return true
}
return false
}
Em meu projeto, tenho um controlador de visualização (Detalhe) que pode ser apresentado modalmente (ao adicionar um novo item) ou com push (ao editar um existente) pelo controlador de visualização Master. Quando o usuário toca em [Concluído], o controlador de visualização de detalhes chama o método do controlador de visualização Mestre para notificar que está pronto para ser fechado. O Mestre deve determinar como o Detalhe é apresentado para saber como fechá-lo. É assim que eu faço isso:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
Um hack como este pode funcionar.
UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
child = parent;
parent = child.parentViewController;
}
if (parent) {
// A view controller in the hierarchy was presented as a modal view controller
}
No entanto, acho que minha resposta anterior é uma solução mais limpa.
O que funcionou para mim é o seguinte:
// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;
// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);
// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];
// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);
Pelo que testei, funciona para iOS7 e iOS8. Porém, não tentei no iOS6.
Eu olhei um pouco ao redor para encontrar a resposta certa para esta pergunta, e não consegui encontrar nenhuma que cobrisse todos os cenários possíveis. Eu escrevi essas poucas linhas de código que parecem fazer o trabalho. Você pode encontrar alguns comentários embutidos para descobrir o que foi verificado.
- (BOOL)isModal {
BOOL modal = NO;
if ([self presentingViewController]) { //Some view Controller is presenting the current stack
UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
}
else {
modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
}
}
return modal;
}
Espero que esta ajuda.
Aqui está minha versão modificada de @GabrielePetronella isModal
, que funciona com controladores de visualização contidos no sentido de que sobe primeiro na hierarquia parentViewController. Também extraiu o código em várias linhas para que fique claro o que está fazendo.
var isModal: Bool {
// If we are a child view controller, we need to check our parent's presentation
// rather than our own. So walk up the chain until we don't see any parentViewControllers
var potentiallyPresentedViewController : UIViewController = self
while (potentiallyPresentedViewController.parentViewController != nil) {
potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
}
if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController {
return true
}
if let navigationController = potentiallyPresentedViewController.navigationController {
if navigationController.presentingViewController?.presentedViewController == navigationController {
return true
}
}
return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}