Представление модального контроллера, не зная текущего контроллера?
Есть ли способ представить контроллер вида, не зная, что такое вид видимого вида контроллера? В принципе, вроде бы вы показывали предупреждение в любой момент времени.
Я хотел бы сделать что-то вроде:
MyViewController *myVC = [[MyViewController alloc] init];
[myVC showModally];
Я хотел бы иметь возможность называть это из любого места приложения и иметь его сверху. Я не хочу заботиться о том, что такое текущий контроллер.
Я планирую использовать это, чтобы показать приглашение для входа. Я не хочу использовать представление предупреждения, и я также не хочу иметь код представления входа во всем приложении.
Любые мысли об этом? Или, может быть, лучший способ добиться этого? Должен ли я просто реализовать свой собственный механизм и просто поместить представление поверх окна?
Ответы
Ответ 1
Ну, вы можете следовать цепочке.
Начните с [UIApplication sharedApplication].delegate.window.rootViewController
.
На каждом контроллере представления выполните следующую последовательность тестов.
Если [viewController isKindOfClass:[UINavigationController class]]
, перейдите к [(UINavigationController *)viewController topViewController]
.
Если [viewController isKindOfClass:[UITabBarController class]]
, перейдите к [(UITabBarController *)viewController selectedViewController]
.
Если [viewController presentedViewController]
, перейдите к [viewController presentedViewController]
.
Ответ 2
Мое решение в Swift (вдохновлено сутью MartinMoizard)
extension UIViewController {
func presentViewControllerFromVisibleViewController(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
if let navigationController = self as? UINavigationController {
navigationController.topViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else if let tabBarController = self as? UITabBarController {
tabBarController.selectedViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else if let presentedViewController = presentedViewController {
presentedViewController.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
} else {
present(viewControllerToPresent, animated: flag, completion: completion)
}
}
}
Ответ 3
Этот код можно реализовать в делетете приложения:
AppDelegate.m
-(void)presentViewControllerFromVisibleController:(UIViewController *)toPresent
{
UIViewController *vc = self.window.rootViewController;
[vc presentViewController:toPresent animated:YES];
}
AppDelegate.h
-(void)presentViewControllerFromVisibleViewController:(UIViewController *)toPresent;
Откуда Где
#import "AppDelegate.h"
...
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
[delegate presentViewControllerFromVisibleViewController:myViewControllerToPresent];
В вашем делегате вы получаете rootViewController
window
. Это всегда будет видно - это "родительский" контроллер всего.
Ответ 4
Это решение дает вам самый популярный контроллер, чтобы вы могли справиться с любыми особыми условиями перед его представлением. Например, возможно, вы хотите представить свой контроллер просмотра только в том случае, если контроллер верхнего уровня не является определенным контроллером представления.
extension UIApplication {
/// The top most view controller
static var topMostViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
}
}
extension UIViewController {
/// The visible view controller from a given view controller
var visibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.visibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.visibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.visibleViewController
} else {
return self
}
}
}
С помощью этого вы можете представить свой контроллер просмотра из любой точки мира, не зная, что находится в верхней части контроллера.
UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)
Или представите свой контроллер просмотра только в том случае, если контроллер верхнего уровня не является определенным контроллером представления.
if let topVC = UIApplication.topMostViewController, !(topVC is FullScreenAlertVC) {
topVC.present(viewController, animated: true, completion: nil)
}
Следует отметить, что если в настоящее время отображается UIAlertController, UIApplication.topMostViewController
вернет UIAlertController
. Представление поверх UIAlertController
имеет странное поведение и его следует избегать. Таким образом, вы должны либо вручную проверить, что !(UIApplication.topMostViewController is UIAlertController)
перед представлением, либо добавить случай else if
для возврата nil, если self is UIAlertController
extension UIViewController {
/// The visible view controller from a given view controller
var visibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.visibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.visibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.visibleViewController
} else if self is UIAlertController {
return nil
} else {
return self
}
}
}
Ответ 5
Я не думаю, что вам обязательно нужно знать, какой контроллер просмотра виден. Вы можете перейти к keyWindow
приложения и добавить вид контроллера модального представления в верхнюю часть списка представлений. Затем вы можете заставить его работать как UIAlertView
.
Файл интерфейса: MyModalViewController.h
#import <UIKit/UIKit.h>
@interface MyModalViewController : UIViewController
- (void) show;
@end
Файл реализации: MyModalViewController.m
#import "MyModalViewController.h"
@implementation MyModalViewController
- (void) show {
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
// Configure the frame of your modal view.
[window addSubview: self.view];
}
@end