Ответы:
Поскольку modalViewController
в iOS 6 она устарела, вот версия, которая работает для iOS 5+ и компилируется без предупреждений.
Objective-C:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
Swift:
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
|| self.tabBarController?.presentingViewController is UITabBarController
}
Подсказка к ответу Фелипе.
nil == nil
возвращается YES
, а это не тот результат, который нам нужен.
Если вы ищете iOS 6+, этот ответ устарел, и вам следует проверить ответ Габриэле Петронеллы.
Нет удобного способа сделать это как свойство или метод, свойственный UIKit. Что вы можете сделать, так это проверить несколько аспектов вашего контроллера, чтобы убедиться, что он представлен как модальный.
Итак, чтобы проверить, представлен ли текущий (представленный self
в приведенном ниже коде) контроллер модальным способом или нет, у меня есть функция, указанная ниже, либо в UIViewController
категории, либо (если вашему проекту не нужно использовать другие контроллеры UIKit, как UITableViewController
например) в базовом контроллере, который наследуются другими моими контроллерами
-(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;
}
РЕДАКТИРОВАТЬ: я добавил последнюю проверку, чтобы увидеть, используется ли UITabBarController, и вы представляете другой UITabBarController как модальный.
РЕДАКТИРОВАТЬ 2: добавлена проверка iOS 5+, где UIViewController
больше не отвечает parentViewController
, а presentingViewController
вместо этого.
РЕДАКТИРОВАТЬ 3: Я создал для него суть на всякий случай https://gist.github.com/3174081
modalViewController
свойство устарело в iOS 6. В документации предлагается использовать его presentedViewController
.
NSLog(@"%@", self.navigationController.parentViewController)
отпечатки (null)
- не могли бы вы объяснить почему? Мой ViewController связан с контроллером модального представления через navController в раскадровке.
.parentViewController
устарела, .presentingViewController
должна использоваться вместо нее .
В iOS5 +, как вы можете видеть в описании класса UIViewController , вы можете получить его из свойства «presentingViewController».
PresentingViewController Контроллер представления, представивший этот контроллер представления. (Только для чтения)
@property (неатомный, только для чтения) UIViewController * PresentingViewController
Обсуждение
Если контроллер представления, получивший это сообщение, представлен другим контроллером представления, это свойство содержит контроллер представления, который его представляет. Если контроллер представления не представлен, но представлен один из его предков, это свойство содержит контроллер представления, представляющий ближайшего предка. Если ни контроллер представления, ни какой-либо из его предков не представлены, это свойство имеет значение nil.
Доступность
Доступно в iOS 5.0 и новее.
Объявлено в
UIViewController.h
presentingViewController
. Он также будет работать в контроллерах представления контейнера, поскольку он автоматически проходит по предкам.
Если нет, вы можете определить свойство для this ( presentedAsModal
) в своем подклассе UIViewController и установить его YES
перед представлением ViewController в виде модального представления.
childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];
Вы можете проверить это значение в своем viewWillAppear
переопределении.
Я считаю, что нет официального свойства, которое бы указывало, как представлено представление, но ничто не мешает вам создать свое собственное.
UINavigationController
модальный ... если только вы не создаете настраиваемый контроллер навигации, чтобы добавить это свойство. И после этого внутри контроллеров вам придется выполнять приведение self.navigationController
к этому пользовательскому классу каждый раз, когда вам нужно проверять, представлен ли контроллер как модальный
Ответ Петронеллы не работает, если self.navigationController представлен модально, но self не равен self.navigationController.viewControllers [0], в этом случае будет отправлено self.
Вот как вы можете решить эту проблему.
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]];
И в 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
Это должно работать.
if(self.parentViewController.modalViewController == self)…
UINavigationController
и UITabBarController
случаев. Пока что это работает довольно хорошо
Лучший способ проверить
if (self.navigationController.presentingViewController) {
NSLog(@"Model Present");
}
Если вам не нужно различать полноэкранные модальные представления и немодальные представления, как в моем проекте (я имел дело с проблемой, которая возникает только с листами форм и листами страниц), вы можете использовать modalPresentationStyle свойство 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;
}
В 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
}
В моем проекте у меня есть контроллер представления (Detail), который может быть представлен либо модально (при добавлении нового элемента), либо с помощью push (при редактировании существующего) с помощью главного контроллера представления. Когда пользователь нажимает [Готово], контроллер детального представления вызывает метод главного контроллера представления, чтобы уведомить о его готовности к закрытию. Мастер должен определить, как Детализация представлена, чтобы знать, как ее закрыть. Вот как я это делаю:
UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
[self dismissViewControllerAnimated:YES completion:NULL];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
Подобный взлом может сработать.
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
}
Однако я думаю, что мой предыдущий ответ - более чистое решение.
Для меня сработало следующее:
// 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);
Насколько я тестировал, это работает для iOS7 и iOS8. Однако на iOS6 не пробовал.
Я немного огляделся, чтобы найти правильный ответ на этот вопрос, и не смог найти ни одного, охватывающего все возможные сценарии. Я написал эти несколько строк кода, которые, кажется, делают свою работу. Вы можете найти несколько встроенных комментариев, чтобы выяснить, что было проверено.
- (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;
}
Надеюсь на эту помощь.
Вот моя модифицированная версия @ GabrielePetronella isModal
, которая работает с автономными контроллерами представления, поскольку сначала проходит по иерархии parentViewController. Также вытащил код на несколько строк, чтобы было понятно, что он делает.
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
}