Как определить, что представлен UIViewController
Я создал подкласс класса UIViewController, который можно либо вставить в стек навигационной системы UINavigationController, либо представить (модально) из любого UIViewController. Мне нужно определить, представлен ли мой контроллер представления, если он представлен, мне нужно добавить панель инструментов с кнопкой закрытия в верхней части контроллера представления. (иначе, если он будет нажат в стек навигации, тогда кнопка закрытия по умолчанию будет добавлена, используя это, пользователь может вернуться назад.)
Во всех доступных версиях, например, 4.3, 5.0, до 6.0, из подкласса UIViewController, могу ли я предположить, что контроллер вида представлен (modally), если выполняется следующее условие.
if(self.parentViewController == nil || self.navigationController == nil)
Ответы
Ответ 1
С iOS 5 UIViewController получил свойство readonly с именем presentingViewController
, которое заменяет старую семантику parentViewController
(которая теперь описывает сдерживание). Это свойство может использоваться, когда диспетчеру просмотра необходимо получить доступ к контроллеру представления, который его представляет - заметьте: это часто будет чем-то другим, чем ожидалось бы, если вы новичок в API!
Кроме того, свойство isBeingPresented
было введено, чтобы в значительной степени решить класс ситуаций, в которые вы сейчас находитесь. Проверьте это свойство в своих контроллерах вида viewWillAppear:
.
Update
Я перепробовал, что вы, похоже, тоже нацелены на iOS 4.3:
В этом случае вам нужно защитить вызов isBeingPresented
с помощью if ([self respondsToSelector:…])
, который вы можете в блоке else
проверить, не является ли parentViewController не нулем.
Другим подходом к обратной совместимости может быть переопределение +resolveInstanceMethod:
для добавления реализации для -isBeingPresented
во время выполнения. Это приведет к тому, что ваши вызывающие сайты будут чистыми, и вы избавитесь от магии времени выполнения, как только вы отпустите поддержку iOS iOS. -)
Заметим, однако, что к этому относятся случаи краев, и вы также начинаете свой подход, когда работаете на iOS < 5:
Контроллер представления может быть представлен в любом другом контроллере представления, включая навигационные контроллеры. Когда этот последний случай случится, вам не повезло: parentViewController
будет nil
, а navigationController
будет не. Вы можете попробовать добавить gobs громоздкого кода, чтобы уменьшить это ограничение в более старых iOSes... или вы могли бы просто отпустить его.
Ответ 2
Я использую этот код, чтобы проверить, представлен ли UIViewController.
if (uiviewcontroller.presentingViewController != nil) {
// do something
}
Ответ 3
У меня был аналогичный случай, однако представленный мной диспетчер представлений завершен в свой собственный контроллер навигации. Поэтому в этом представлении контроллер, когда мне нужно определить, добавлять ли кнопку закрытия к задней кнопке, , я просто проверяю размер стека контроллеров навигации. Если представлен экран, размер стека должен быть одним (требуется кнопка закрытия)... и если он будет нажат с помощью существующего контроллера навигации, размер стека будет больше одного (требуется кнопка возврата).
BOOL presented = [[self.navigationController viewControllers] count] == 1;
Ответ 4
Чтобы справиться с таким поведением, я обычно устанавливаю / reset BOOL, переключая его в viewWillAppear/viewWillDisappear.
Кстати, ваше тестовое состояние кажется неправильным. Я думаю, вы должны использовать
if(self.parentViewController != nil || self.navigationController != nil)
Почему вы не можете просто добавить панель инструментов в свой контроллер? Есть ли случай, когда представление загружено, но не представлено?
Ответ 5
@saikamesh.
Поскольку вы используете UINavigationController для навигации по вашим диспетчеру просмотра, я думаю, вы можете использовать topViewController
(Doc здесь) и visibleViewController
(Doc снова), чтобы достичь ваших целей.
Вы упомянули, что:
когда он помещается в стек навигации, тогда кнопка закрытия по умолчанию будет добавлен, если пользователь сможет вернуться назад
Если экземпляр конкретного UIViewController важен, я думаю, что лучше создать общий одноэлементный экземпляр и предоставить глобальный флаг:
id specificVC = [SpecificViewController sharedInstance];
if (specificVC.isPushed) {
[self.navController popToViewController:specificVC animated:YES];
}
и проверить, представлен ли он:
if ([self.navController.visibleViewController isKindOfClass:[SpecificViewController class]]) {
// Hide or add close button
self.isPresented = YES;
}
Или вы можете прочитать принятый ответ.
:) Надежда помогает.
Ответ 6
Пожалуйста, проверьте этот способ:
for (UIViewController*vc in [self.navigationController viewControllers]) {
if ([vc isKindOfClass: [OffersViewController class]]){ //this line also checks OffersViewController is presented or not
if(vc.isViewLoaded){
NSLog(@"Yes");
}
}
}
Ответ 7
Вы можете сделать это так, быстро и безопасно
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
// Find the top controller on the view hierarchy
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
// If the top controller it is not already presented
if (![topController isKindOfClass:[YourViewController class]]) {
// Present it
[topController presentViewController:yourViewController animated:YES completion:nil];
}
else {
// do some stuff here
}
Ответ 8
В любой момент вы можете проверить, есть ли у вас контроллер модального представления или нет, используя свойство modalViewController из вашего навигационного контроллера.
Пример:
UIViewController *presentedController = self.navigationController.modalViewController;
if (presentedController) {
// At this point, you have a view controller presented from your navigation controller
if ([presentedController isKindOfClass:[controllerYouWantToCheck class]]) {
// add your toolbar/buttons/etc here
}
}
Ответ 9
Один из элегантных ответов, которые я не видел здесь:
// Edit: Added 2 other modal cases
extension UIViewController {
var isModal: Bool {
return self.presentingViewController?.presentedViewController == self
|| (navigationController != nil && navigationController?.presentingViewController?.presentedViewController == navigationController)
|| tabBarController?.presentingViewController is UITabBarController
}
}
кредит: на основе этот смысл
Ответ 10
В Swift на iOS 9 (или позже):
if viewController.viewIfLoaded?.window != nil {
// viewController is visible
}
Ответ 11
Если бы это был я, у меня был бы специальный метод init и его использование при создании vc.
vc = [[[MyUIViewControllerSubClass alloc] init] initWithToolbarAndCloseButton:YES];
Ответ 12
Небольшая модификация в ответе @AmitaiB для создания функции,
func isModallyPresented(tmpVC:UIViewController) -> Bool {
return tmpVC.presentingViewController?.presentedViewController == tmpVC
|| (tmpVC.navigationController != nil && tmpVC.navigationController?.presentingViewController?.presentedViewController == tmpVC.navigationController)
|| tmpVC.tabBarController?.presentingViewController is UITabBarController
}
Просто проверьте по телефону:
if(isModallyPresented(tmpVC:myTopVC)){
//return true if viewcontroller is presented
}
Ответ 13
Как сказал Мартин Рид, это лучший способ
BOOL presented = [[self.navigationController viewControllers] count] == 1;
if (presented) {
[self dismissViewControllerAnimated:YES completion:^{
// do whatever you need here
}];
}
else {
[self.navigationController popViewControllerAnimated:YES];
}