如何在使用storyboard时从app delegate获取可见的viewController?

时间:2014-04-05 14:20:44

标签: ios

我有一些viewControllers,我不使用NavigationController。 如何在应用委托方法中获取可见的视图控制器(例如applicationWillResignActive)?

我知道如何从NSNotification开始,但我认为这是错误的方式。

14 个答案:

答案 0 :(得分:49)

这应该适合你:

- (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];
}

答案 1 :(得分:34)

@ 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
}

答案 2 :(得分:8)

我们将其实现为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
    }
}

答案 3 :(得分:3)

这是Swift中一种递归的,面向协议的方法。可以扩展为自定义类型,但任何类型的UIViewController子类都应该使用下面的代码。

/admin/books/create 
/admin/books/1/edit

答案 4 :(得分:3)

此处的最佳建议在许多情况下都可以正常运行以获得最佳猜测解决方案,但只需进行一些小的调整,我们就可以获得更完整的解决方案。 39; t依赖于应用程序的视图层次结构实现。

1)Cocoa Touch的视图层次结构允许多个孩子同时出现并可见,因此我们需要改为询问当前可见的视图控制器(复数)并相应地处理结果

2)UINavigationControllerUITabBarController s常用于iOS应用程序,但它们不是唯一一种容器视图控制器。 UIKit还提供UIPageViewControllerUISplitViewController,并允许您编写自己的自定义容器视图控制器。

3)我们可能想忽略popover模式和特定类型的视图控制器,例如UIAlertController或自定义嵌入式子视图控制器。

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 []
    }
}

答案 5 :(得分:3)

以下是Swift 4中的答案,它与已接受的答案非常相似,但有一些改进:

  1. 迭代而不是递归。
  2. 一直走到导航堆栈。
  3. 更多“swifty”语法。
  4. 可以放在任何地方的静态变量(不仅仅是在AppDelegate中)。
  5. 奇怪情况下不会崩溃,即当标签栏控制器没有选定的视图控制器时。

    static var visibleViewController: UIViewController? {
        var currentVc = UIApplication.shared.keyWindow?.rootViewController
        while let presentedVc = currentVc?.presentedViewController {
            if let navVc = (presentedVc as? UINavigationController)?.viewControllers.last {
                currentVc = navVc
            } else if let tabVc = (presentedVc as? UITabBarController)?.selectedViewController {
                currentVc = tabVc
            } else {
                currentVc = presentedVc
            }
        }
        return currentVc
    }
    

答案 6 :(得分:2)

如果你的应用程序的根视图控制器是UINavigationController而不是你可以使用它:

UIViewController *currentControllerName = ((UINavigationController*)appDelegate.window.rootViewController).visibleViewController;

如果你使用UITabBarController,你可以使用它:

UIViewController *currentControllerName = ((UITabBarController*)appDelegate.window.rootViewController).selectedViewController;

答案 7 :(得分:2)

如果您使用的是IQKeyboardManager,那么他们就有一个扩展

  • (UIViewController中*)currentViewController;

所以你可以做到

 application.keyWindow?.currentViewController? // <- there you go

将其添加到您的pod文件

pod 'IQKeyboardManager'

then pod update and you are away!

希望这会有所帮助

答案 8 :(得分:1)

这是@ProgrammierTier答案的改进版本。如果导航栏嵌套在选项卡中,则将使用@ProgrammierTier的答案返回UINavigationController。同样,解开力的情况也更少。这应该解决@ Harendra-Tiwari面临的问题。

Swift 4.2:

func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? {

  var rootVC = rootViewController
  if rootVC == nil {
      rootVC = UIApplication.shared.keyWindow?.rootViewController
  }

  var presented = rootVC?.presentedViewController
  if rootVC?.presentedViewController == nil {
      if let isTab = rootVC?.isKind(of: UITabBarController.self), let isNav = rootVC?.isKind(of: UINavigationController.self) {
          if !isTab && !isNav {
              return rootVC
          }
          presented = rootVC
      } else {
          return rootVC
      }
  }

  if let presented = presented {
    if presented.isKind(of: UINavigationController.self) {
        if let navigationController = presented as? UINavigationController {
            return navigationController.viewControllers.last!
        }
     }

     if presented.isKind(of: UITabBarController.self) {
        if let tabBarController = presented as? UITabBarController {
            if let navigationController = tabBarController.selectedViewController! as? UINavigationController {
                 return navigationController.viewControllers.last!
             } else {
                 return tabBarController.selectedViewController!
             }
         }
     }

     return getVisibleViewController(presented)
  }
  return nil
}

答案 9 :(得分:0)

这是@ ProgrammierTier作为UIViewController扩展的答案的Swift 2.3实现

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
}

答案 10 :(得分:0)

在我的情况下,我有Tabbar控制器,然后每个Tab的导航控制器希望它可以帮助某人

 UIViewController *loginViewController=self.window.rootViewController;

 UITabBarController *controller=loginViewController.tabBarController;

 UIViewController *CurrentController = controller.selectedViewController.childViewControllers.lastObject;

答案 11 :(得分:0)

这里只是来自@ krcjr89答案的快速修复。 接受的答案不会一直沿着导航。例如,如果您在标签栏控制器中嵌入了导航控制器,则无法访问可见视图控制器,而是导航控制器。

我把它作为@Christian的UIApplication的扩展,因为这是最有意义的。

extension UIApplication {
    var visibleViewController: UIViewController? {
        return getVisibleViewController(nil)
    }

    private func getVisibleViewController(_ rootViewController: UIViewController?) -> UIViewController? {

        let rootVC = rootViewController ?? UIApplication.shared.keyWindow?.rootViewController

        if rootVC!.isKind(of: UINavigationController.self) {
            let navigationController = rootVC as! UINavigationController
            return getVisibleViewController(navigationController.viewControllers.last!)
        }

        if rootVC!.isKind(of: UITabBarController.self) {
            let tabBarController = rootVC as! UITabBarController
            return getVisibleViewController(tabBarController.selectedViewController!)
        }

        if let presentedVC = rootVC?.presentedViewController {
            return getVisibleViewController(presentedVC)
        }

        return rootVC
    }
}

答案 12 :(得分:0)

使用ObjC中的UIViewController类别的先前答案的修改版本:

<强>的UIViewController + VisibleViewController.h

#import <UIKit/UIKit.h>

@interface UIViewController (VisibleViewController)

- (UIViewController *)visibleViewController;

@end

<强>的UIViewController + VisibleViewController.m

#import "UIViewController+VisibleViewController.h"

@implementation UIViewController (VisibleViewController)

- (UIViewController *)visibleViewController {
    if (self.presentedViewController == nil) {
        return self;
    }
    if ([self.presentedViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController *navigationController = (UINavigationController *)self.presentedViewController;
        UIViewController *lastViewController = [[navigationController viewControllers] lastObject];

        return [lastViewController visibleViewController];
    }
    if ([self.presentedViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController *tabBarController = (UITabBarController *)self.presentedViewController;
        UIViewController *selectedViewController = tabBarController.selectedViewController;

        return [selectedViewController visibleViewController];
    }

    UIViewController *presentedViewController = (UIViewController *)self.presentedViewController;

    return [presentedViewController visibleViewController];
}

@end

<强> AppDelegate.m

#import "UIViewController+VisibleViewController.h"

- (UIViewController *) applicationVisibleViewController {
    return [self.window.rootViewController visibleViewController];
}

答案 13 :(得分:-1)

从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;
}