Відповіді:
Оскільки modalViewController
заставлено в iOS 6, ось версія, яка працює для iOS 5+ і компілюється без попереджень.
Завдання-C:
- (BOOL)isModal {
return self.presentingViewController.presentedViewController == self
|| (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
|| [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}
Швидкий:
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;
}
EDIT: Я додав останню перевірку, щоб перевірити, чи використовується UITabBarController, і ви представляєте інший UITabBarController як модальний.
EDIT 2: додано чек для iOS 5+, де UIViewController
вже не відповідає parentViewController
, а presentingViewController
замість цього.
EDIT 3: Я створив для цього суть лише на випадок https://gist.github.com/3174081
modalViewController
властивість застаріло на iOS 6. Документація пропонує presentedViewController
замість цього використовувати .
NSLog(@"%@", self.navigationController.parentViewController)
відбитки (null)
- ви могли б пояснити, чому? Мій ViewController з'єднаний з контролером модального перегляду через navController у розкадровці.
.parentViewController
застарілий, .presentingViewController
замість цього потрібно використовувати.
У iOS5 +, як ви бачите в UIViewController Class Reference , ви можете отримати його з властивості "presentingViewController".
ПредставленняViewController Контролер подання, який представив цей контролер подання. (лише для читання)
@ властивість (неатомічна, лише для читання) UIViewController * presentingViewController
Discussion
Якщо контролер перегляду, який отримав це повідомлення, представлений іншим контролером перегляду, ця властивість містить контролер перегляду, який його представляє. Якщо контролер подання не представлений, але представлений один з його предків, ця властивість містить контролер подання, який представляє найближчого предка. Якщо ні представник контролера, ні хтось із його предків не представлені, ця властивість не відповідає нулю.
Доступність
Доступно в iOS 5.0 та новіших версіях.
Задекларовано в
UIViewController.h
presentingViewController
. Він також працюватиме в контролерах перегляду контейнерів, оскільки він автоматично обходить предків.
Якщо цього немає, ви можете визначити властивість для цього ( 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]];
І в Свіфті:
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;
}
У Свіфті :
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), який можна представити або модально (при додаванні нового елемента), або з натисканням (при редагуванні існуючого) контролером Master view. Коли користувач натискає [Готово], контролер детального перегляду викликає метод контролера головного перегляду, щоб повідомити, що він готовий закритись. Майстер повинен визначити, як детально представлений, щоб знати, як його закрити. Ось як я це роблю:
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
}