I can\'t seem to get the top most UIViewController
without access to a UINavigationController
. Here is what I have so far:
UIApplic
In a very rare case, with custom segue, the top most view controller is not in a navigation stack or tab bar controller or presented, but its view is inserted to the top of key windown's subviews.
In such situation, it's necessary to check if UIApplication.shared.keyWindow.subviews.last == self.view
to determine if the current view controller is the top most.
iOS13+ //top Most view Controller
extension UIViewController {
func topMostViewController() -> UIViewController {
if self.presentedViewController == nil {
return self
}
if let navigation = self.presentedViewController as? UINavigationController {
return navigation.visibleViewController!.topMostViewController()
}
if let tab = self.presentedViewController as? UITabBarController {
if let selectedTab = tab.selectedViewController {
return selectedTab.topMostViewController()
}
return tab.topMostViewController()
}
return self.presentedViewController!.topMostViewController()
}
}
extension UIApplication {
func topMostViewController() -> UIViewController? {
return UIWindow.key!.rootViewController?.topMostViewController()
}
}
extension UIWindow {
static var key: UIWindow? {
if #available(iOS 13, *) {
return UIApplication.shared.windows.first { $0.isKeyWindow }
} else {
return UIApplication.shared.keyWindow
}
}
}
//use let vc = UIApplication.shared.topMostViewController()
// End top Most view Controller
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
}
I loved @dianz's answer, and so here is the swift 3's version of it. It's basically the same thing but his was missing a curly brace and some of the syntax/variable/method names have changed. So here it is!
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}
Usage is still the exact same though:
if let topController = UIApplication.topViewController() {
print("The view controller you're looking at is: \(topController)")
}
To find the visible viewController in Swift 3
if let viewControllers = window?.rootViewController?.childViewControllers {
let prefs = UserDefaults.standard
if viewControllers[viewControllers.count - 1] is ABCController{
print("[ABCController] is visible")
}
}
This code find the last added or the last active controller visible.
This I have used in AppDelegate to find active view Controller
presentViewController
shows a view controller. It doesn't return a view controller. If you're not using a UINavigationController
, you're probably looking for presentedViewController
and you'll need to start at the root and iterate down through the presented views.
if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}
For Swift 3+:
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}
For iOS 13+
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}