如果无法访问UIViewController
,我似乎无法获得最高UINavigationController
。以下是我到目前为止的情况:
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(vc, animated: true, completion: nil)
然而,它似乎没有做任何事情。 keyWindow
和rootViewController
似乎也是非零值,因此可选链接应该不是问题。
注意: 做这样的事情是个坏主意。它破坏了MVC模式。
答案 0 :(得分:242)
有此扩展程序
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
}
}
您可以在控制器的任何位置使用它
if let topController = UIApplication.topViewController() {
}
答案 1 :(得分:227)
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
}
答案 2 :(得分:27)
快速4/5 +获取最顶级的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)
}
答案 3 :(得分:15)
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)
}
答案 4 :(得分:6)
基于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;
}
答案 5 :(得分:5)
我喜欢@dianz's answer,所以这里是它的快速3版本。它基本上是相同的,但他缺少大括号,一些语法/变量/方法名称已经改变。所以这就是它!
ster = "*"
space = " "
lines = 0
n = 3
x = 1
while lines <= 5:
print space*n, ster*x
n-= 1
x+= 1
lines += 1
但用法仍然完全相同:
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
}
}
答案 6 :(得分:5)
使用此代码查找最顶层的UIViewController
func getTopViewController() -> UIViewController? {
var topController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController
while topController?.presentedViewController != nil {
topController = topController?.presentedViewController
}
return topController
}
答案 7 :(得分:5)
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()
}
}
然后,通过以下方式获取顶部的viewController:
UIApplication.shared.topMostViewController()
答案 8 :(得分:4)
使用计算变量而不是函数对@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
}
答案 9 :(得分:4)
基于上面的Bob -c:
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;
}
}
}
}
答案 10 :(得分:3)
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
}
}
答案 11 :(得分:3)
对于 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
}
}
}
用法:
在没有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)
答案 12 :(得分:2)
在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中使用它来查找活动视图Controller
答案 13 :(得分:2)
你可以在AppDelegate中定义一个UIViewController变量,并在每个viewWillAppear中将变量设置为self。(但是dianz的答案是最好的答案。)
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let appDel = UIApplication.sharedApplication().delegate as! AppDelegate
appDel.currentVC = self
}
答案 14 :(得分:2)
iOS13 + //顶部大多数视图控制器
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
答案 15 :(得分:1)
斯威夫特 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())
答案 16 :(得分:1)
对于任何寻求快速5 / iOS 13+解决方案的人(自iOS 13起,keywindow
被弃用)
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
}
}
}
答案 17 :(得分:1)
在极少数情况下,使用自定义序列,最顶部的视图控制器不在导航堆栈或选项卡栏控制器中或未显示,而是将其视图插入到关键windown子视图的顶部。
在这种情况下,有必要检查UIApplication.shared.keyWindow.subviews.last == self.view
是否确定当前视图控制器是否是最高的。
答案 18 :(得分:1)
太多的口味,但没有一个反复阐述。结合以前的内容:
"took": 84,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 248,
"max_score": 1,
"hits": [
{
"_index": "countries-codes",
"_type": "event",
"_id": "Gx_gEGoBP2qGR-HHGMw3",
"_score": 1,
"_source": {
"name": "Albanie",
"alpha_2": "AL",
"alpha_3": "ALB",
"num": "8"
}
},
答案 19 :(得分:1)
你把代码放在哪里?
我在我的演示中尝试了你的代码,我发现,如果你把代码放在
中func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
将失败,因为关键窗口已设置。
但我把你的代码放在某个视图控制器的
中override func viewDidLoad() {
它只是有效。
答案 20 :(得分:0)
对我来说最好的解决方案是使用功能扩展。 使用此扩展名创建一个快捷文件
首先是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
}
答案 21 :(得分:0)
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()
}
}
答案 22 :(得分:0)
var topViewController: UIViewController? {
guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
while let presentedViewController = topViewController.presentedViewController {
topViewController = presentedViewController
}
return topViewController
}
答案 23 :(得分:0)
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
}
答案 24 :(得分:0)
在 SWIFT 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
}
}
答案 25 :(得分:0)
runningTotal
Swift 5.2及更高版本
答案 26 :(得分:0)
我使用下面的代码来获取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)