Как получить видимый viewController из делегата приложения при использовании раскадровки?
У меня есть viewControllers
, и я не использую NavigationController
.
Как я могу получить видимый контроллер представления в методах делегатов приложения (например, applicationWillResignActive
)?
Я знаю, как это сделать из NSNotification
, но я думаю, что это неправильно.
Ответы
Ответ 1
Это должно сделать это за вас:
- (void)applicationWillResignActive:(UIApplication *)application
{
UIViewController *vc = [self visibleViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController *)visibleViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil)
{
return rootViewController;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self visibleViewController:lastViewController];
}
if ([rootViewController.presentedViewController isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)rootViewController.presentedViewController;
UIViewController *selectedViewController = tabBarController.selectedViewController;
return [self visibleViewController:selectedViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self visibleViewController:presentedViewController];
}
Ответ 2
@aviatorken89 ответ работал хорошо для меня. Мне пришлось перевести его на Swift -
для любого начинающего с Swift:
Обновлено для Swift 3:
func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? {
var rootVC = rootViewController
if rootVC == nil {
rootVC = UIApplication.shared.keyWindow?.rootViewController
}
if rootVC?.presentedViewController == nil {
return rootVC
}
if let presented = rootVC?.presentedViewController {
if presented.isKind(of: UINavigationController.self) {
let navigationController = presented as! UINavigationController
return navigationController.viewControllers.last!
}
if presented.isKind(of: UITabBarController.self) {
let tabBarController = presented as! UITabBarController
return tabBarController.selectedViewController!
}
return getVisibleViewController(presented)
}
return nil
}
Старый ответ:
func applicationWillResignActive(application: UIApplication) {
let currentViewController = getVisibleViewController(nil)
}
func getVisibleViewController(var rootViewController: UIViewController?) -> UIViewController? {
if rootViewController == nil {
rootViewController = UIApplication.sharedApplication().keyWindow?.rootViewController
}
if rootViewController?.presentedViewController == nil {
return rootViewController
}
if let presented = rootViewController?.presentedViewController {
if presented.isKindOfClass(UINavigationController) {
let navigationController = presented as! UINavigationController
return navigationController.viewControllers.last!
}
if presented.isKindOfClass(UITabBarController) {
let tabBarController = presented as! UITabBarController
return tabBarController.selectedViewController!
}
return getVisibleViewController(presented)
}
return nil
}
Ответ 3
Мы реализовали его как расширение UIApplication:
import UIKit
extension UIApplication {
var visibleViewController: UIViewController? {
guard let rootViewController = keyWindow?.rootViewController else {
return nil
}
return getVisibleViewController(rootViewController)
}
private func getVisibleViewController(_ rootViewController: UIViewController) -> UIViewController? {
if let presentedViewController = rootViewController.presentedViewController {
return getVisibleViewController(presentedViewController)
}
if let navigationController = rootViewController as? UINavigationController {
return navigationController.visibleViewController
}
if let tabBarController = rootViewController as? UITabBarController {
return tabBarController.selectedViewController
}
return rootViewController
}
}
Ответ 4
Вот рекурсивный, ориентированный на протокол подход в Swift. Может быть расширен до пользовательских типов, но любой подкласс UIViewController должен работать с кодом ниже.
public protocol ViewControllerContainer {
var topMostViewController: UIViewController? { get }
}
extension UIViewController: ViewControllerContainer {
public var topMostViewController: UIViewController? {
if let presentedView = presentedViewController {
return recurseViewController(presentedView)
}
return childViewControllers.last.map(recurseViewController)
}
}
extension UITabBarController {
public override var topMostViewController: UIViewController? {
return selectedViewController.map(recurseViewController)
}
}
extension UINavigationController {
public override var topMostViewController: UIViewController? {
return viewControllers.last.map(recurseViewController)
}
}
extension UIWindow: ViewControllerContainer {
public var topMostViewController: UIViewController? {
return rootViewController.map(recurseViewController)
}
}
func recurseViewController(viewController: UIViewController) -> UIViewController {
return viewController.topMostViewController.map(recurseViewController) ?? viewController
}
Ответ 5
Если ваш контроллер представления корневого приложения является UINavigationController, вы можете использовать это:
UIViewController *currentControllerName = ((UINavigationController*)appDelegate.window.rootViewController).visibleViewController;
и если вы используете UITabBarController, вы можете использовать это:
UIViewController *currentControllerName = ((UITabBarController*)appDelegate.window.rootViewController).selectedViewController;
Ответ 6
Лучшие рекомендации здесь будут хорошо работать во многих сценариях, чтобы получить "лучшее предположение", но с небольшими корректировками, мы можем получить более полное решение, которое не зависит от реализации иерархии представления приложения.
1) Cocoa Иерархия сенсорного представления позволяет одновременному присутствию и видимости нескольких дочерних элементов, поэтому нам нужно вместо этого запрашивать текущие видимые контроллеры (множественное число) и обрабатывать результаты соответственно.
2) UINavigationController
и UITabBarController
обычно используются в приложениях iOS, но они не являются единственным видом контроллеров контейнеров. UIKit также предоставляет UIPageViewController
, UISplitViewController
и позволяет вам создавать собственные настраиваемые контроллеры контейнеров.
3) Мы, вероятно, хотим игнорировать модификаторы popover и определенные типы контроллеров представлений, такие как UIAlertController
или собственный встроенный контроллер child-view.
private func visibleViewControllers() -> [UIViewController] {
guard let root = window?.rootViewController else { return [] }
return visibleLeaves(from: root, excluding: [UIAlertController.self])
}
private func visibleLeaves(from parent: UIViewController, excluding excludedTypes: [UIViewController.Type] = []) -> [UIViewController] {
let isExcluded: (UIViewController) -> Bool = { vc in
excludedTypes.contains(where: { vc.isKind(of: $0) }) || vc.modalPresentationStyle == .popover
}
if let presented = parent.presentedViewController, !isExcluded(presented) {
return self.visibleLeaves(from: presented, excluding: excludedTypes)
}
let visibleChildren = parent.childViewControllers.filter {
$0.isViewLoaded && $0.view.window != nil
}
let visibleLeaves = visibleChildren.flatMap {
return self.visibleLeaves(from: $0, excluding: excludedTypes)
}
if visibleLeaves.count > 0 {
return visibleLeaves
} else if !isExcluded(parent) {
return [parent]
} else {
return []
}
}
Ответ 7
Здесь реализация Swift 2.3 @ProgrammierTier отвечает как расширение для UIViewController
extension UIViewController {
var visibleViewController: UIViewController? {
if presentedViewController == nil {
return self
}
if let presented = presentedViewController {
if presented.isKindOfClass(UINavigationController) {
let navigationController = presented as! UINavigationController
return navigationController.viewControllers.last
}
if presented.isKindOfClass(UITabBarController) {
let tabBarController = presented as! UITabBarController
return tabBarController.selectedViewController
}
return presented.visibleViewController
}
return nil
}
}
Чтобы получить его от applicationWillResignActive
func applicationWillResignActive(application: UIApplication) {
let visibleVC = application.keyWindow?.rootViewController?.visibleViewController
}
Ответ 8
В моем случае у меня есть контроллер Tabbar, а затем контроллер навигации для каждой вкладки надеется, что это поможет кому-то
UIViewController *loginViewController=self.window.rootViewController;
UITabBarController *controller=loginViewController.tabBarController;
UIViewController *CurrentController = controller.selectedViewController.childViewControllers.lastObject;
Ответ 9
Если вы используете IQKeyboardManager, там есть расширение
- (UIViewController *) currentViewController;
чтобы вы могли сделать
application.keyWindow?.currentViewController? // <- there you go
поэтому добавьте это в свой файл pod
pod 'IQKeyboardManager'
then pod update and you are away!
надеюсь, что это поможет
Ответ 10
изменен из troop231
+ (UIViewController *)visibleViewController:(UIViewController *)rootViewController
{
if ([rootViewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)rootViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self visibleViewController:lastViewController];
}
if ([rootViewController isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
UIViewController *selectedViewController = tabBarController.selectedViewController;
return [self visibleViewController:selectedViewController];
}
if (rootViewController.presentedViewController != nil)
{
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self visibleViewController:presentedViewController];
}
return rootViewController;
}