「最上位」のビューコントローラ(現在のビューを担当するもの)を見つけることができれば便利な場合がいくつかありますが、その方法が見つかりませんでした。
基本的な課題はこれです。View Controllerではないクラスで実行する(またはビュー) )[アクティブなビューのアドレスは持っていません]そして最上位のビューコントローラのアドレス(またはナビゲーションコントローラのアドレスなど)が渡されていないそのView Controllerを見つけることは可能ですか? (そして、もしそうなら、どうやって?)
それとも失敗したとしても、最上位のビューを見つけることは可能ですか?
iOS 4では、UIWindowにrootViewControllerプロパティが導入されました。
[UIApplication sharedApplication].keyWindow.rootViewController;
View Controllerを作成した後で自分で設定する必要があります。
私はあなたが承認された答えと@ fishstixのの組み合わせが必要だと思います
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
Swift 3.0以降
func topMostController() -> UIViewController? {
guard let window = UIApplication.shared.keyWindow, let rootViewController = window.rootViewController else {
return nil
}
var topController = rootViewController
while let newTopController = topController.presentedViewController {
topController = newTopController
}
return topController
}
JonasGの answer (トラバース中にTab Bar Controllerを省いた人)を完成させるために、現在表示されているView Controllerを返すバージョンを次に示します。
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
さまざまなシナリオに対応した、完全な非再帰バージョン。
UINavigationController
です。UITabBarController
です。Objective-C
UIViewController *topViewController = self.window.rootViewController;
while (true)
{
if (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
} else if ([topViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)topViewController;
topViewController = nav.topViewController;
} else if ([topViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tab = (UITabBarController *)topViewController;
topViewController = tab.selectedViewController;
} else {
break;
}
}
Swift 4 +
extension UIWindow {
func topViewController() -> UIViewController? {
var top = self.rootViewController
while true {
if let presented = top?.presentedViewController {
top = presented
} else if let nav = top as? UINavigationController {
top = nav.visibleViewController
} else if let tab = top as? UITabBarController {
top = tab.selectedViewController
} else {
break
}
}
return top
}
}
拡張機能を使用してSwiftの最上位のView Controllerを取得する
コード:
extension UIViewController {
@objc func topMostViewController() -> UIViewController {
// Handling Modal views
if let presentedViewController = self.presentedViewController {
return presentedViewController.topMostViewController()
}
// Handling UIViewController's added as subviews to some other views.
else {
for view in self.view.subviews
{
// Key property which most of us are unaware of / rarely use.
if let subViewController = view.next {
if subViewController is UIViewController {
let viewController = subViewController as! UIViewController
return viewController.topMostViewController()
}
}
}
return self
}
}
}
extension UITabBarController {
override func topMostViewController() -> UIViewController {
return self.selectedViewController!.topMostViewController()
}
}
extension UINavigationController {
override func topMostViewController() -> UIViewController {
return self.visibleViewController!.topMostViewController()
}
}
使用法
UIApplication.sharedApplication().keyWindow!.rootViewController!.topMostViewController()
Ericの answer (ポップオーバー、ナビゲーションコントローラ、タブバーコントローラ、トラバース中に他のView Controllerにサブビューとして追加されたView Controllerを省略したもの)を完成させるために、現在表示されているView Controllerを返します。
=================================================== ===================
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)viewController {
if ([viewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)viewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([viewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navContObj = (UINavigationController*)viewController;
return [self topViewControllerWithRootViewController:navContObj.visibleViewController];
} else if (viewController.presentedViewController && !viewController.presentedViewController.isBeingDismissed) {
UIViewController* presentedViewController = viewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
}
else {
for (UIView *view in [viewController.view subviews])
{
id subViewController = [view nextResponder];
if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
{
if ([(UIViewController *)subViewController presentedViewController] && ![subViewController presentedViewController].isBeingDismissed) {
return [self topViewControllerWithRootViewController:[(UIViewController *)subViewController presentedViewController]];
}
}
}
return viewController;
}
}
=================================================== ===================
そして今、あなたが一番上のView Controllerを手に入れるためにする必要があるのは、次のように上記のメソッドを呼び出すことです:
UIViewController *topMostViewControllerObj = [self topViewController];
この回答にはchildViewControllers
が含まれており、きれいで読みやすい実装を維持しています。
+ (UIViewController *)topViewController
{
UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
return [rootViewController topVisibleViewController];
}
- (UIViewController *)topVisibleViewController
{
if ([self isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)self;
return [tabBarController.selectedViewController topVisibleViewController];
}
else if ([self isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)self;
return [navigationController.visibleViewController topVisibleViewController];
}
else if (self.presentedViewController)
{
return [self.presentedViewController topVisibleViewController];
}
else if (self.childViewControllers.count > 0)
{
return [self.childViewControllers.lastObject topVisibleViewController];
}
return self;
}
私は最近私のプロジェクトでこの状況に遭遇しました、それは表示されたコントローラが何であっても、そしてタイプがどんなものでも(UINavigationController、クラシックコントローラまたはカスタムView Controller)通知ビューを表示する必要がありました。
それで私は自分のコードをリリースしました。それはとても簡単で実際にはプロトコルに基づいているので、あらゆるタイプのコンテナコントローラに柔軟に対応できます。それは最後の答えに関連しているようですが、非常に柔軟な方法です。
あなたはここでコードをつかむことができます: PPTopMostController
そして一番上のコントローラを使って
UIViewController *c = [UIViewController topMostController];
これはEricの答えに対する改善です。
UIViewController *_topMostController(UIViewController *cont) {
UIViewController *topController = cont;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
if ([topController isKindOfClass:[UINavigationController class]]) {
UIViewController *visible = ((UINavigationController *)topController).visibleViewController;
if (visible) {
topController = visible;
}
}
return (topController != cont ? topController : nil);
}
UIViewController *topMostController() {
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
UIViewController *next = nil;
while ((next = _topMostController(topController)) != nil) {
topController = next;
}
return topController;
}
_topMostController(UIViewController *cont)
はヘルパー関数です。
今、あなたがする必要があるのはtopMostController()
を呼び出すことだけです、そして、一番上のUIViewControllerは返されるべきです!
- (UIViewController*)topViewController {
return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
SwiftでのUIApplication
の簡単な拡張子:
注:
moreNavigationController
内のUITabBarController
を気にしています
extension UIApplication {
class func topViewController(baseViewController: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = baseViewController as? UINavigationController {
return topViewController(navigationController.visibleViewController)
}
if let tabBarViewController = baseViewController as? UITabBarController {
let moreNavigationController = tabBarViewController.moreNavigationController
if let topViewController = moreNavigationController.topViewController where topViewController.view.window != nil {
return topViewController(topViewController)
} else if let selectedViewController = tabBarViewController.selectedViewController {
return topViewController(selectedViewController)
}
}
if let splitViewController = baseViewController as? UISplitViewController where splitViewController.viewControllers.count == 1 {
return topViewController(splitViewController.viewControllers[0])
}
if let presentedViewController = baseViewController?.presentedViewController {
return topViewController(presentedViewController)
}
return baseViewController
}
}
簡単な使い方
if let topViewController = UIApplication.topViewController() {
//do sth with top view controller
}
これが私の考えです。 UIAlertViewを最上位コントローラにすることをスキップする方法を指摘してくれた@Stakenborgに感謝
-(UIWindow *) returnWindowWithWindowLevelNormal
{
NSArray *windows = [UIApplication sharedApplication].windows;
for(UIWindow *topWindow in windows)
{
if (topWindow.windowLevel == UIWindowLevelNormal)
return topWindow;
}
return [UIApplication sharedApplication].keyWindow;
}
-(UIViewController *) getTopMostController
{
UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
if (topWindow.windowLevel != UIWindowLevelNormal)
{
topWindow = [self returnWindowWithWindowLevelNormal];
}
UIViewController *topController = topWindow.rootViewController;
if(topController == nil)
{
topWindow = [UIApplication sharedApplication].delegate.window;
if (topWindow.windowLevel != UIWindowLevelNormal)
{
topWindow = [self returnWindowWithWindowLevelNormal];
}
topController = topWindow.rootViewController;
}
while(topController.presentedViewController)
{
topController = topController.presentedViewController;
}
if([topController isKindOfClass:[UINavigationController class]])
{
UINavigationController *nav = (UINavigationController*)topController;
topController = [nav.viewControllers lastObject];
while(topController.presentedViewController)
{
topController = topController.presentedViewController;
}
}
return topController;
}
@実装UIWindow(拡張) - (UIViewController *)topMostController { UIViewController * topController = [self rootViewController]; while(topController.prentedViewController){ topController = topController.prepresentViewController; [.____。}} topControllerを返す; } @終わり
最新のSwiftバージョンの場合
ファイルを作成し、UIWindowExtension.Swift
という名前を付けて、以下のコードを貼り付けます。
import UIKit
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
func getTopViewController() -> UIViewController? {
let appDelegate = UIApplication.sharedApplication().delegate
if let window = appDelegate!.window {
return window?.visibleViewController
}
return nil
}
としてどこでもそれを使用します。
if let topVC = getTopViewController() {
}
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
}
}
どこからでも使えます、
UIApplication.topViewController()?.present(yourController, animated: true, completion: nil)
または好き
UIApplication.topViewController()?
.navigationController?
.popToViewController(yourController,
animated: true)
UINavigationController、UITabBarControllerなどのあらゆるクラスに適合
楽しい!
これは私のために働いたものです。
KeyWindowはアラートなどのようなOSのものであるため、私は時々コントローラーがキーウィンドウ上でゼロであることを発見しました。
+ (UIViewController*)topMostController
{
UIWindow *topWndow = [UIApplication sharedApplication].keyWindow;
UIViewController *topController = topWndow.rootViewController;
if (topController == nil)
{
// The windows in the array are ordered from back to front by window level; thus,
// the last window in the array is on top of all other app windows.
for (UIWindow *aWndow in [[UIApplication sharedApplication].windows reverseObjectEnumerator])
{
topController = aWndow.rootViewController;
if (topController)
break;
}
}
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}
代替のSwiftソリューション:
static func topMostController() -> UIViewController {
var topController = UIApplication.sharedApplication().keyWindow?.rootViewController
while (topController?.presentedViewController != nil) {
topController = topController?.presentedViewController
}
return topController!
}
@ Ericの答えを拡張して、あなたはkeyWindowが実際にあなたが望むウィンドウであることに注意する必要があります。たとえば、アラートビューで何かをタップした後にこのメソッドを使用しようとしている場合、実際にはkeyWindowがアラートのウィンドウになるので、それが問題になることは間違いありません。アラートを介してディープリンクを処理するとき、これは実際に私に起こりました、そしてNO STACK TRACEを持つSIGABRTを引き起こしました。デバッグする総雌犬。
これが私が今使っているコードです:
- (UIViewController *)getTopMostViewController {
UIWindow *topWindow = [UIApplication sharedApplication].keyWindow;
if (topWindow.windowLevel != UIWindowLevelNormal) {
NSArray *windows = [UIApplication sharedApplication].windows;
for(topWindow in windows)
{
if (topWindow.windowLevel == UIWindowLevelNormal)
break;
}
}
UIViewController *topViewController = topWindow.rootViewController;
while (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
}
return topViewController;
}
この質問の他の答えからあなたが好きなトップビューコントローラを取得するどんな風味とでも自由にこれを混ぜてください。
この解決策は最も完全です。それは考慮に入れます:UINavigationController UIPageViewController UITabBarControllerそしてトップビューコントローラから一番上に提示されたビューコントローラ
例はSwift 3にあります。
3過負荷があります
//Get the topmost view controller for the current application.
public func MGGetTopMostViewController() -> UIViewController? {
if let currentWindow:UIWindow = UIApplication.shared.keyWindow {
return MGGetTopMostViewController(fromWindow: currentWindow)
}
return nil
}
//Gets the topmost view controller from a specific window.
public func MGGetTopMostViewController(fromWindow window:UIWindow) -> UIViewController? {
if let rootViewController:UIViewController = window.rootViewController
{
return MGGetTopMostViewController(fromViewController: rootViewController)
}
return nil
}
//Gets the topmost view controller starting from a specific UIViewController
//Pass the rootViewController into this to get the apps top most view controller
public func MGGetTopMostViewController(fromViewController viewController:UIViewController) -> UIViewController {
//UINavigationController
if let navigationViewController:UINavigationController = viewController as? UINavigationController {
let viewControllers:[UIViewController] = navigationViewController.viewControllers
if navigationViewController.viewControllers.count >= 1 {
return MGGetTopMostViewController(fromViewController: viewControllers[viewControllers.count - 1])
}
}
//UIPageViewController
if let pageViewController:UIPageViewController = viewController as? UIPageViewController {
if let viewControllers:[UIViewController] = pageViewController.viewControllers {
if viewControllers.count >= 1 {
return MGGetTopMostViewController(fromViewController: viewControllers[0])
}
}
}
//UITabViewController
if let tabBarController:UITabBarController = viewController as? UITabBarController {
if let selectedViewController:UIViewController = tabBarController.selectedViewController {
return MGGetTopMostViewController(fromViewController: selectedViewController)
}
}
//Lastly, Attempt to get the topmost presented view controller
var presentedViewController:UIViewController! = viewController.presentedViewController
var nextPresentedViewController:UIViewController! = presentedViewController?.presentedViewController
//If there is a presented view controller, get the top most prensentedViewController and return it.
if presentedViewController != nil {
while nextPresentedViewController != nil {
//Set the presented view controller as the next one.
presentedViewController = nextPresentedViewController
//Attempt to get the next presented view controller
nextPresentedViewController = presentedViewController.presentedViewController
}
return presentedViewController
}
//If there is no topmost presented view controller, return the view controller itself.
return viewController
}
さらに別のSwiftソリューション
func topController() -> UIViewController? {
// recursive follow
func follow(from:UIViewController?) -> UIViewController? {
if let to = (from as? UITabBarController)?.selectedViewController {
return follow(to)
} else if let to = (from as? UINavigationController)?.visibleViewController {
return follow(to)
} else if let to = from?.presentedViewController {
return follow(to)
}
return from
}
let root = UIApplication.sharedApplication().keyWindow?.rootViewController
return follow(root)
}
私はほとんどの答えがUINavigationViewController
を完全に無視していると思うので、このユースケースは次のような実装で処理しました。
+ (UIViewController *)topMostController {
UIViewController * topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController || [topController isMemberOfClass:[UINavigationController class]]) {
if([topController isMemberOfClass:[UINavigationController class]]) {
topController = [topController childViewControllers].lastObject;
} else {
topController = topController.presentedViewController;
}
}
return topController;
}
Swiftの優れたソリューション、AppDelegateに実装
func getTopViewController()->UIViewController{
return topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!)
}
func topViewControllerWithRootViewController(rootViewController:UIViewController)->UIViewController{
if rootViewController is UITabBarController{
let tabBarController = rootViewController as! UITabBarController
return topViewControllerWithRootViewController(tabBarController.selectedViewController!)
}
if rootViewController is UINavigationController{
let navBarController = rootViewController as! UINavigationController
return topViewControllerWithRootViewController(navBarController.visibleViewController)
}
if let presentedViewController = rootViewController.presentedViewController {
return topViewControllerWithRootViewController(presentedViewController)
}
return rootViewController
}
そしてもう一つのSwiftソリューション
extension UIViewController {
static var topmostViewController: UIViewController? {
return UIApplication.sharedApplication().keyWindow?.topmostViewController
}
var topmostViewController: UIViewController? {
return presentedViewController?.topmostViewController ?? self
}
}
extension UINavigationController {
override var topmostViewController: UIViewController? {
return visibleViewController?.topmostViewController
}
}
extension UITabBarController {
override var topmostViewController: UIViewController? {
return selectedViewController?.topmostViewController
}
}
extension UIWindow {
var topmostViewController: UIViewController? {
return rootViewController?.topmostViewController
}
}
以下の2つの関数は、View ControllerのスタックでtopViewControllerを見つけるのに役立ちます。後でカスタマイズする必要があるかもしれませんが、このコードではtopViewControllerまたはviewControllerのスタックの概念を理解するのは素晴らしいです。
- (UIViewController*)findTopViewController {
id topControler = [self topMostController];
UIViewController* topViewController;
if([topControler isKindOfClass:[UINavigationController class]]) {
topViewController = [[(UINavigationController*)topControler viewControllers] lastObject];
} else if ([topControler isKindOfClass:[UITabBarController class]]) {
//Here you can get reference of top viewcontroller from stack of viewcontrollers on UITabBarController
} else {
//topController is a preented viewController
topViewController = (UIViewController*)topControler;
}
//NSLog(@"Top ViewController is: %@",NSStringFromClass([topController class]));
return topViewController;
}
- (UIViewController*)topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
//NSLog(@"Top View is: %@",NSStringFromClass([topController class]));
return topController;
}
[viewController Class]メソッドを使って、viewControllerのクラスの種類を調べることができます。
迅速:
extension UIWindow {
func visibleViewController() -> UIViewController? {
if let rootViewController: UIViewController = self.rootViewController {
return UIWindow.getVisibleViewControllerFrom(rootViewController)
}
return nil
}
class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {
if vc.isKindOfClass(UINavigationController.self) {
let navigationController = vc as UINavigationController
return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)
} else if vc.isKindOfClass(UITabBarController.self) {
let tabBarController = vc as UITabBarController
return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)
} else {
if let presentedViewController = vc.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)
} else {
return vc;
}
}
}
使用法:
if let topController = window.visibleViewController() {
println(topController)
}
これらの答えの多くは不完全です。これはObjective-Cに含まれていますが、これは私が今のところまとめておくことができる、再帰的でないブロックとして、それらすべてのうちの最高のコンパイルです。
Gistへのリンク。改訂された場合は、 https://Gist.github.com/benguild/0d149bb3caaabea2dac3d2dca58c0816
参照/比較のためのコード:
UIViewController *(^topmostViewControllerForFrontmostNormalLevelWindow)(void) = ^UIViewController *{
// NOTE: Adapted from various stray answers here:
// https://stackoverflow.com/questions/6131205/iphone-how-to-find-topmost-view-controller/20515681
UIViewController *viewController;
for (UIWindow *window in UIApplication.sharedApplication.windows.reverseObjectEnumerator.allObjects) {
if (window.windowLevel == UIWindowLevelNormal) {
viewController = window.rootViewController;
break;
}
}
while (viewController != nil) {
if ([viewController isKindOfClass:[UITabBarController class]]) {
viewController = ((UITabBarController *)viewController).selectedViewController;
} else if ([viewController isKindOfClass:[UINavigationController class]]) {
viewController = ((UINavigationController *)viewController).visibleViewController;
} else if (viewController.presentedViewController != nil && !viewController.presentedViewController.isBeingDismissed) {
viewController = viewController.presentedViewController;
} else if (viewController.childViewControllers.count > 0) {
viewController = viewController.childViewControllers.lastObject;
} else {
BOOL repeat = NO;
for (UIView *view in viewController.view.subviews.reverseObjectEnumerator.allObjects) {
if ([view.nextResponder isKindOfClass:[UIViewController class]]) {
viewController = (UIViewController *)view.nextResponder;
repeat = YES;
break;
}
}
if (!repeat) {
break;
}
}
}
return viewController;
};
現在表示されているUIViewController
を取得するには、以下の拡張子を使用してください。 Swift 4.0以降で動作しました
コード:
extension UIApplication {
class func topViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = viewController as? UINavigationController {
return topViewController(nav.visibleViewController)
}
if let tab = viewController as? UITabBarController {
if let selected = tab.selectedViewController {
return topViewController(selected)
}
}
if let presented = viewController?.presentedViewController {
return topViewController(presented)
}
return viewController
}
}
使い方は?
let objViewcontroller = UIApplication.topViewController()
一番上のView Controllerを見つけることでこれが達成しようとしていることに役立つかどうかはわかりませんが、新しいView Controllerを表示しようとしていました。このコードを使用して、すべてのモーダルView Controllerの先頭に移動します。
UIViewController* parentController =[UIApplication sharedApplication].keyWindow.rootViewController;
while( parentController.presentedViewController &&
parentController != parentController.presentedViewController )
{
parentController = parentController.presentedViewController;
}
多くの複雑さを避けるために、デリゲートにviewControllerを作成し、各viewDidLoadメソッド内でそれを自分自身に設定することによって現在のviewControllerを追跡します。 。これは醜いかもしれませんが、それは素晴らしく動作し、そしてナビゲーションコントローラやそのナンセンスのいずれかを持っている必要はありません。
ルートコントローラがナビゲーションコントローラの場合、一番上に見えるコントローラを見つける正しい方法は次のとおりです。
UIViewController *rootVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
if ([rootVC respondsToSelector:@selector(visibleViewController)])
{
UIViewController *topVC = [(UINavigationController *)rootVC visibleViewController];
// do your thing with topVC
}
これがUINavigationController.hからの抜粋です。
@property(nonatomic,readonly,retain) UIViewController *topViewController; // The top view controller on the stack.
@property(nonatomic,readonly,retain) UIViewController *visibleViewController; // Return modal view controller if it exists. Otherwise the top view controller.
これは、トップビューコントローラーを見つけるのに最適です 1 任意のルートビューコントローラーから
+ (UIViewController *)topViewControllerFor:(UIViewController *)viewController
{
if(!viewController.presentedViewController)
return viewController;
return [MF5AppDelegate topViewControllerFor:viewController.presentedViewController];
}
/* View Controller for Visible View */
AppDelegate *app = [UIApplication sharedApplication].delegate;
UIViewController *visibleViewController = [AppDelegate topViewControllerFor:app.window.rootViewController];
私の問題は私のアプリケーションでSWRevealViewControllerを使っているのとは少し違いました。私はYuchen Zhongの answer を使用しましたが、それは常にSWRevealViewControllerとしてtopViewControllerを返します。 sideMenuを開発するためにSWRevealViewControllerまたは他のポッドを使用している人のために。これがYuchen Zhongの答えに対する私の拡張です:
extension UIApplication {
class func topViewController() -> UIViewController? {
var topVC = shared.keyWindow!.rootViewController
while true {
if let presented = topVC?.presentedViewController {
topVC = presented
} else if let nav = topVC as? UINavigationController {
topVC = nav.visibleViewController
} else if let tab = topVC as? UITabBarController {
topVC = tab.selectedViewController
}else if let swRVC = topVC as? SWRevealViewController {
topVC = swRVC.frontViewController
} else {
break
}
}
return topVC
}
}
前の回答では、rootControllerがUITabBarControllerまたはUINavigationControllerであるケースを処理できないようです。
これらの場合に機能するSwiftの関数は次のとおりです。
func getCurrentView() -> UIViewController?
{
if let window = UIApplication.sharedApplication().keyWindow, var currentView: UIViewController = window.rootViewController
{
while (currentView.presentedViewController != nil)
{
if let presented = currentView.presentedViewController
{
currentView = presented
}
}
if currentView is UITabBarController
{
if let visible = (currentView as! UITabBarController).selectedViewController
{
currentView = visible;
}
}
if currentView is UINavigationController
{
if let visible = (currentView as! UINavigationController).visibleViewController
{
currentView = visible;
}
}
return currentView
}
return nil
}
おそらくここで見落とされていることが1つあると思います。おそらく、viewControllerを使用している関数に親のviewControllerを渡す方が良いでしょう。あなたがそれがおそらくモデル層とUI層の分離に違反していて、それがコードの匂いであることをトップのView Controllerを見つけるためにビューの階層構造の周りを釣り合っているならば。これを指摘するだけで、私は同じことをしました、そしてそれから私がView Controllerへの参照を持っているUI層にモデル操作を戻すことによってそれを機能に渡すことがはるかに簡単であることに気付きました。
を使用して、一番上のView Controllerを見つけることができます。
NSArray *arrViewControllers=[[self navigationController] viewControllers];
UIViewController *topMostViewController=(UIViewController *)[arrViewControllers objectAtIndex:[arrViewControllers count]-1];
これは、ルートとしてUINavigationControllerを使ったSwiftによるアプリケーションの実装です。
if let nav = UIApplication.sharedApplication().keyWindow?.rootViewController as? UINavigationController{
//get the current's navigation view controller
var vc = nav.topViewController
while vc?.presentedViewController != nil {
vc = vc?.presentedViewController
}
return vc
}
私はRajeshによる解決策はほぼ完璧だと思いますが、上から下へのサブビューを横断するのがより良いと思います、私は次のように変更しました:
+ (UIViewController *)topViewController:(UIViewController *)viewController{
if (viewController.presentedViewController)
{
UIViewController *presentedViewController = viewController.presentedViewController;
return [self topViewController:presentedViewController];
}
else if ([viewController isKindOfClass:[UITabBarController class]])
{
UITabBarController *tabBarController = (UITabBarController *)viewController;
return [self topViewController:tabBarController.selectedViewController];
}
else if ([viewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)viewController;
return [self topViewController:navController.visibleViewController];
}
// Handling UIViewController's added as subviews to some other views.
else {
NSInteger subCount = [viewController.view subviews].count - 1;
for (NSInteger index = subCount; index >=0 ; --index)
{
UIView *view = [[viewController.view subviews] objectAtIndex:index];
id subViewController = [view nextResponder]; // Key property which most of us are unaware of / rarely use.
if ( subViewController && [subViewController isKindOfClass:[UIViewController class]])
{
return [self topViewController:subViewController];
}
}
return viewController;
}
}
別の解決策はレスポンダチェーンに依存します。これは、最初のレスポンダが何であるかに応じて動作する場合と動作しない場合があります。
疑似コードの例:
+ (UIViewController *)currentViewController {
UIView *firstResponder = [self firstResponder]; // from the first link above, but not guaranteed to return a UIView, so this should be handled more appropriately.
UIViewController *viewController = [firstResponder viewController]; // from the second link above
return viewController;
}
Swift 4.2の簡潔で包括的なソリューションでは、INavigationControllers、ITabBarControllers、提示およびchildのView Controllerを考慮しています。
extension UIViewController {
func topmostViewController() -> UIViewController {
if let navigationVC = self as? UINavigationController,
let topVC = navigationVC.topViewController {
return topVC.topmostViewController()
}
if let tabBarVC = self as? UITabBarController,
let selectedVC = tabBarVC.selectedViewController {
return selectedVC.topmostViewController()
}
if let presentedVC = presentedViewController {
return presentedVC.topmostViewController()
}
if let childVC = children.last {
return childVC.topmostViewController()
}
return self
}
}
extension UIApplication {
func topmostViewController() -> UIViewController? {
return keyWindow?.rootViewController?.topmostViewController()
}
}
使用法:
let viewController = UIApplication.shared.topmostViewController()