I can\'t seem to get the top most UIViewController
without access to a UINavigationController
. Here is what I have so far:
UIApplic
have this extension
Swift 2.*
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(presented)
}
return controller
}
}
Swift 3
extension UIApplication {
class func topViewController(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewController(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewController(controller: presented)
}
return controller
}
}
You can you use this anywhere on your controller
if let topController = UIApplication.topViewController() {
}
you can define a UIViewController variable in AppDelegate, and in every viewWillAppear set the variable to self.(however dianz answer is the best answer.)
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
appDel.currentVC = self
}
Based on Bob -c above:
Swift 3.0
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKind(of: UINavigationController.self) {
let navigationController = vc as! UINavigationController
return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!)
} else if vc.isKind(of: UITabBarController.self) {
let tabBarController = vc as! UITabBarController
return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!)
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController)
} else {
return vc;
}
}
}
}
import UIKit
extension UIApplication {
// MARK: Choose keyWindow as per your choice
var currentWindow: UIWindow? {
connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
}
// MARK: Choose keyWindow as per your choice
var keyWindow: UIWindow? {
UIApplication.shared.windows.first { $0.isKeyWindow }
}
class func topMostViewController(base: UIViewController? = UIApplication.shared.currentWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topMostViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController, top.view.window != nil {
return topMostViewController(base: top)
} else if let selected = tab.selectedViewController {
return topMostViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topMostViewController(base: presented)
}
return base
}
}
Use this code to find top most UIViewController
func getTopViewController() -> UIViewController? {
var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}
For Swift 5+, iOS 13+
extension UIViewController {
static func topMostViewController() -> UIViewController? {
if #available(iOS 13.0, *) {
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
return keyWindow?.rootViewController?.topMostViewController()
}
return UIApplication.shared.keyWindow?.rootViewController?.topMostViewController()
}
func topMostViewController() -> UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.topMostViewController()
}
else if let tabBarController = self as? UITabBarController {
if let selectedViewController = tabBarController.selectedViewController {
return selectedViewController.topMostViewController()
}
return tabBarController.topMostViewController()
}
else if let presentedViewController = self.presentedViewController {
return presentedViewController.topMostViewController()
}
else {
return self
}
}
}
Usage:
When you are getting topMostViewController without instance of UIViewController
guard let viewController = UIViewController.topMostViewController() else { return }
print(viewController)
When you are getting topMostViewController of instance of UIViewController
let yourVC = UIViewController()
guard let vc = yourVC.topMostViewController() else { return }
print(vc)