获取最顶端的UIViewController

我似乎不能得到顶部最UIViewController没有访问UINavigationController。以下是我目前所掌握的:

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil)

然而,它似乎没有做任何事情。keyWindowrootViewController似乎也是非空值,所以可选的链接应该不是问题。

注意: 做这样的事是个坏主意。它打破了MVC模式。

222572 次浏览

presentViewController显示了一个视图控制器。它不会返回一个视图控制器。如果你没有使用UINavigationController,你可能正在寻找presentedViewController,你需要从根开始,向下迭代所呈现的视图。

if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}


// topController should now be your topmost view controller
}

对于Swift 3+:

if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}


// topController should now be your topmost view controller
}

适用于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
}

你把密码放哪了?

我在我的演示中尝试了你的代码,我发现,如果你把代码放进去

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

将失败,因为关键窗口已经设置。

但我把你的代码放到了视图控制器中

override func viewDidLoad() {

它就是有用。

extension UIWindow {


func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
}
return nil
}


static func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if let navigationController = vc as? UINavigationController,
let visibleController = navigationController.visibleViewController  {
return UIWindow.getVisibleViewControllerFrom( vc: visibleController )
} else if let tabBarController = vc as? UITabBarController,
let selectedTabController = tabBarController.selectedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: selectedTabController )
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController)
} else {
return vc
}
}
}
}

用法:

if let topController = window.visibleViewController() {
println(topController)
}

有这个扩展

斯威夫特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
}
}

斯威夫特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
}
}

然后你可以在控制器的任何地方使用它

if let topController = UIApplication.topViewController() {
    

}

基于Dianz的答案,Objective-C版本

- (UIViewController *) topViewController {
UIViewController *baseVC = UIApplication.sharedApplication.keyWindow.rootViewController;
if ([baseVC isKindOfClass:[UINavigationController class]]) {
return ((UINavigationController *)baseVC).visibleViewController;
}


if ([baseVC isKindOfClass:[UITabBarController class]]) {
UIViewController *selectedTVC = ((UITabBarController*)baseVC).selectedViewController;
if (selectedTVC) {
return selectedTVC;
}
}


if (baseVC.presentedViewController) {
return baseVC.presentedViewController;
}
return baseVC;
}

我喜欢@dianz的回答,所以这里是它的swift 3的版本。它基本上是一样的,但他少了一个大括号,一些语法/变量/方法名已经改变了。所以它就在这里!

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

用法仍然是一样的:

if let topController = UIApplication.topViewController() {
print("The view controller you're looking at is: \(topController)")
}

你可以在AppDelegate中定义一个UIViewController变量,并在每个viewWillAppear中设置这个变量为self。(然而,dianz的答案是最好的答案。)

override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
appDel.currentVC = self
}

在Swift 3中找到可见的viewController

if let viewControllers = window?.rootViewController?.childViewControllers {


let prefs = UserDefaults.standard


if viewControllers[viewControllers.count - 1] is ABCController{
print("[ABCController] is visible")


}
}

这段代码找到最后添加的或最后可见的活动控制器。

我已经在AppDelegate中使用它来查找活动视图控制器

基于上面的Bob -c:

斯威夫特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;
}
}
}
}

使用这段代码找到top most UIViewController

func getTopViewController() -> UIViewController? {
var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}

对于swift 4 / 5 +获取topmost viewController

// MARK: UIApplication extensions


extension UIApplication {


class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {


if let nav = base as? UINavigationController {
return getTopViewController(base: nav.visibleViewController)


} else if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
return getTopViewController(base: selected)


} else if let presented = base?.presentedViewController {
return getTopViewController(base: presented)
}
return base
}
}

如何使用

if let topVC = UIApplication.getTopViewController() {
topVC.view.addSubview(forgotPwdView)
}

https://gist.github.com/db0company/369bfa43cb84b145dfd8 我对这个网站上的答案和评论做了一些测试。对我来说,下面的工作

extension UIViewController {
func topMostViewController() -> UIViewController {


if let presented = self.presentedViewController {
return presented.topMostViewController()
}


if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController() ?? navigation
}


if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController() ?? tab
}


return self
}
}


extension UIApplication {
func topMostViewController() -> UIViewController? {
return self.keyWindow?.rootViewController?.topMostViewController()
}
}

然后,通过以下方法获取top viewController:

UIApplication.shared.topMostViewController()

@AlberZou略有变化,使用计算变量而不是函数

extension UIViewController {
var topMostViewController : UIViewController {


if let presented = self.presentedViewController {
return presented.topMostViewController
}


if let navigation = self as? UINavigationController {
return navigation.visibleViewController?.topMostViewController ?? navigation
}


if let tab = self as? UITabBarController {
return tab.selectedViewController?.topMostViewController ?? tab
}


return self
}
}


extension UIApplication {
var topMostViewController : UIViewController? {
return self.keyWindow?.rootViewController?.topMostViewController
}
}

然后说

if let topViewControler = UIApplication.shared.topMostViewController {
... do stuff
}

在一个非常罕见的情况下,使用自定义segue,最顶层的视图控制器不在导航堆栈或选项卡栏控制器中或被呈现,但它的视图被插入到关键窗口子视图的顶部。

在这种情况下,有必要检查UIApplication.shared.keyWindow.subviews.last == self.view来确定当前视图控制器是否是最顶层的。

太多口味了,但都不是一种反复精心制作的。结合前面的内容:

     func topMostController() -> UIViewController? {
var from = UIApplication.shared.keyWindow?.rootViewController
while (from != nil) {
if let to = (from as? UITabBarController)?.selectedViewController {
from = to
} else if let to = (from as? UINavigationController)?.visibleViewController {
from = to
} else if let to = from?.presentedViewController {
from = to
} else {
break
}
}
return from
}
  var topViewController: UIViewController? {
guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
while let presentedViewController = topViewController.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}
对我来说最好的解决方案是一个带有函数的扩展。 创建一个swift文件,扩展名为

首先是UIWindow扩展:

public extension UIWindow {
var visibleViewController: UIViewController? {
return UIWindow.visibleVC(vc: self.rootViewController)
}


static func visibleVC(vc: UIViewController?) -> UIViewController? {
if let navigationViewController = vc as? UINavigationController {
return UIWindow.visibleVC(vc: navigationViewController.visibleViewController)
} else if let tabBarVC = vc as? UITabBarController {
return UIWindow.visibleVC(vc: tabBarVC.selectedViewController)
} else {
if let presentedVC = vc?.presentedViewController {
return UIWindow.visibleVC(vc: presentedVC)
} else {
return vc
}
}
}
}

在该文件中添加函数

func visibleViewController() -> UIViewController? {
let appDelegate = UIApplication.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
如果你想使用它,你可以在任何地方调用它。 示例< / >强:

  override func viewDidLoad() {
super.viewDidLoad()
if let topVC = visibleViewController() {
//show some label or text field
}
}

文件代码是这样的:

import UIKit


public extension UIWindow {
var visibleViewController: UIViewController? {
return UIWindow.visibleVC(vc: self.rootViewController)
}


static func visibleVC(vc: UIViewController?) -> UIViewController? {
if let navigationViewController = vc as? UINavigationController {
return UIWindow.visibleVC(vc: navigationViewController.visibleViewController)
} else if let tabBarVC = vc as? UITabBarController {
return UIWindow.visibleVC(vc: tabBarVC.selectedViewController)
} else {
if let presentedVC = vc?.presentedViewController {
return UIWindow.visibleVC(vc: presentedVC)
} else {
return vc
}
}
}
}


func visibleViewController() -> UIViewController? {
let appDelegate = UIApplication.shared.delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
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
}
}

对于任何寻找快速5/iOS 13+解决方案的人(keywindow自iOS 13以来已弃用)

extension UIApplication {


class func getTopMostViewController() -> UIViewController? {
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
} else {
return nil
}
}
}
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 self.keyWindow?.rootViewController?.topMostViewController()
}
}
斯威夫特5 + < p >, 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
}
}
}

用法:

当你在没有UIViewController实例的情况下获取topMostViewController时

guard let viewController = UIViewController.topMostViewController() else { return }
print(viewController)

当你获取UIViewController实例的topMostViewController时

let yourVC = UIViewController()
guard let vc = yourVC.topMostViewController() else { return }
print(vc)
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
}

iOS13 + //top大多数视图控制器

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

斯威夫特5.2

你可以使用下面的代码:

import UIKit


extension UIWindow {
static func getTopViewController() -> UIViewController? {
if #available(iOS 13, *){
let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
            

if var topController = keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
}
} else {
if var topController = UIApplication.shared.keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
return topController
}
}
return nil
}
}
    extension UIApplication {
        

public var mainKeyWindow: UIWindow? {
if #available(iOS 13, *) {
return UIApplication.shared.connectedScenes
.filter { $0.activationState == .foregroundActive }
.first(where: { $0 is UIWindowScene })
.flatMap { $0 as? UIWindowScene }?.windows
.first(where: \.isKeyWindow)
} else {
return UIApplication.shared.windows.first { $0.isKeyWindow }
}
}
    



public var rootViewController: UIViewController? {
guard let keyWindow = UIApplication.shared.mainKeyWindow, let rootViewController = keyWindow.rootViewController else {
return nil
}
return rootViewController
}


public func topViewController(controller: UIViewController? = UIApplication.shared.rootViewController) -> UIViewController? {


if controller == nil {
return topViewController(controller: rootViewController)
}
        

if let navigationController = controller as? UINavigationController {
return topViewController(controller: navigationController.visibleViewController)
}


if let tabController = controller as? UITabBarController {
if let selectedViewController = tabController.selectedViewController {
return topViewController(controller: selectedViewController)
}
}


if let presentedViewController = controller?.presentedViewController {
return topViewController(controller: presentedViewController)
}


return controller
}
}

Swift 5.2及以上版本

我使用下面的代码来获得topViewController-

向后兼容旧的iOS版本&也负责UIScene

extension UIApplication {
func topViewController() -> UIViewController? {
var topViewController: UIViewController? = nil
if #available(iOS 13, *) {
for scene in connectedScenes {
if let windowScene = scene as? UIWindowScene {
for window in windowScene.windows {
if window.isKeyWindow {
topViewController = window.rootViewController
}
}
}
}
} else {
topViewController = keyWindow?.rootViewController
}
while true {
if let presented = topViewController?.presentedViewController {
topViewController = presented
} else if let navController = topViewController as? UINavigationController {
topViewController = navController.topViewController
} else if let tabBarController = topViewController as? UITabBarController {
topViewController = tabBarController.selectedViewController
} else {
// Handle any other third party container in `else if` if required
break
}
}
return topViewController
}
}

它可以这样使用:

let topController = UIApplication.shared.topViewController()
topController?.present(controllerToPresent, animated: true, completion: nil)

斯威夫特5 +

声明

func topViewController() -> UIViewController? {
    

let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first


if var topController = keyWindow?.rootViewController {
        

while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
        

return topController
        

} else {
        

return nil
        

}
    

}

使用

topViewController()?.view.addSubview(UIView())

最简单的方法是从视图控制器堆栈中取出最后一个:

if let viewController: UIViewController = navigationController.viewControllers.last {
// This `viewController` is on the top.
}

试试这个

let topVisibleVC = UIApplication.shared.keyWindow?.rootViewController?.visibleViewController