Подтвердить что ты не робот

Как получить видимый viewController из делегата приложения при использовании раскадровки?

У меня есть viewControllers, и я не использую NavigationController. Как я могу получить видимый контроллер представления в методах делегатов приложения (например, applicationWillResignActive)?

Я знаю, как это сделать из NSNotification, но я думаю, что это неправильно.

4b9b3361

Ответ 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;
}