web-dev-qa-db-ja.com

一番上のUIViewControllerを入手

UIViewControllerにアクセスしないと、一番上のUINavigationControllerを取得できないようです。これが私がこれまでに持っているものです:

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

しかし、何もしていないようです。 keyWindowおよびrootViewControllerもnil以外の値であるように思われるので、オプションの連鎖は問題にならないはずです。

注:このようなことをするのは悪い考えです。 MVCパターンを破る

159
Zoyt

presentViewControllerはビューコントローラを示します。 View Controllerを返しません。 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
}
229
rickerbh

この拡張子を持っている

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

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() {

}
242
dianz

Swift 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)
}
29
Hardik Thakkar
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)
}
15
Bobj-C

Objective-CバージョンDianzの回答に基づく

- (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;
}
6
Tibidabo

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()
5
Albert Zou

このコードを使用して、最も上位にあるUIViewControllerを見つけます。

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

私は大好きだった @ dianz's answer だから、これが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)")
}
5
Ponyboy47

上記のBob-cに基づきます。

Swift 3.

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;
            }
        }
    }
}
4
Daniel

関数ではなく計算変数を使用した@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
}
4
Ryan Heitner

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でアクティブなView Controllerを見つけるために使用しました

2
Prateekro

appDelegateでUIViewController変数を定義し、すべてのviewWillAppearで変数をselfに設定することができます(ただし、dianzの回答が最良の回答です)。

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

フレーバーが多すぎますが、反復的なものではありませんでした。前のものと組み合わせて:

     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
    }
1
Jaime Agudo

ごくまれに、カスタムセグエで、最上位のView ControllerがナビゲーションスタックまたはTab Bar Controllerに含まれていないか表示されていないが、そのビューが主要なWindownのサブビューの最上位に挿入されている。

このような状況では、現在のView Controllerが最上位であるかどうかを判断するためにUIApplication.shared.keyWindow.subviews.last == self.viewを確認する必要があります。

1
BabyPanda

どこにコードを入れましたか?

私のデモであなたのコードを試してみます。

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

キーウィンドウはまだ設定されているので失敗します。

しかし、私はあなたのコードをいくつかのView Controllerに入れます。

override func viewDidLoad() {

それだけでうまくいきます。

1
Tinyfool

私にとって最良の解決策は、機能を備えた拡張機能です。この拡張子を持つ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
}
0
tBug
  var topViewController: UIViewController? {
        guard var topViewController = UIApplication.shared.keyWindow?.rootViewController else { return nil }
        while let presentedViewController = topViewController.presentedViewController {
            topViewController = presentedViewController
        }
        return topViewController
    }
0
Den