在不知道当前视图控制器的情况下呈现模态控制器?

neb*_*ebs 21 modal-dialog presentmodalviewcontroller ios

有没有办法在不知道可见视图控制器视图是什么的情况下以模态方式呈现视图控制器?基本上有点像你会在任何时间点显示警报视图.

我希望能够做到这样的事情:

MyViewController *myVC = [[MyViewController alloc] init];
[myVC showModally];
Run Code Online (Sandbox Code Playgroud)

我希望能够从应用程序的任何位置调用此功能,并将其显示在顶部.我不想关心当前的视图控制器是什么.

我打算用它来显示登录提示.我不想使用警报视图,我也不希望在整个应用程序中都有登录演示代码.

有什么想法吗?或者有没有更好的方法来实现这一目标?我应该只实现自己的机制,只是在窗口顶部放置一个视图?

Jef*_*mas 29

那么,你可以跟随链.

从...开始[UIApplication sharedApplication].delegate.window.rootViewController.

在每个视图控制器上执行以下一系列测试.

如果[viewController isKindOfClass:[UINavigationController class]],那么继续[(UINavigationController *)viewController topViewController].

如果[viewController isKindOfClass:[UITabBarController class]],那么继续[(UITabBarController *)viewController selectedViewController].

如果[viewController presentedViewController],那么继续[viewController presentedViewController].


all*_*ire 20

我在Swift中的解决方案(灵感来自MartinMoizard的要点)

extension UIViewController {
    func presentViewControllerFromVisibleViewController(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
        if let navigationController = self as? UINavigationController {
            navigationController.topViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
        } else if let tabBarController = self as? UITabBarController {
            tabBarController.selectedViewController?.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
        } else if let presentedViewController = presentedViewController {
            presentedViewController.presentViewControllerFromVisibleViewController(viewControllerToPresent, animated: flag, completion: completion)
        } else {
            present(viewControllerToPresent, animated: flag, completion: completion)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


NSE*_*nal 10

此解决方案为您提供最顶层的视图控制器,以便您可以在呈现之前处理任何特殊条件.例如,您可能只想在最顶层视图控制器不是特定视图控制器时才显示视图控制器.

extension UIApplication {
    /// The top most view controller
    static var topMostViewController: UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
    }
}

extension UIViewController {
    /// The visible view controller from a given view controller
    var visibleViewController: UIViewController? {
        if let navigationController = self as? UINavigationController {
            return navigationController.topViewController?.visibleViewController
        } else if let tabBarController = self as? UITabBarController {
            return tabBarController.selectedViewController?.visibleViewController
        } else if let presentedViewController = presentedViewController {
            return presentedViewController.visibleViewController
        } else {
            return self
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有了它,您可以从任何地方展示您的视图控制器,而无需知道最顶级的视图控制器是什么

UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)

或仅在最顶层视图控制器不是特定视图控制器时显示视图控制器

if let topVC = UIApplication.topMostViewController, !(topVC is FullScreenAlertVC) {
    topVC.present(viewController, animated: true, completion: nil)
}
Run Code Online (Sandbox Code Playgroud)

需要注意的一点是,如果当前正在显示UIAlertController,UIApplication.topMostViewController则会返回一个UIAlertController.在a之上呈现UIAlertController有奇怪的行为,应该避免.因此,您应该!(UIApplication.topMostViewController is UIAlertController)在呈现之前手动检查,或者添加一个else if案例以返回nil ifself is UIAlertController

extension UIViewController {
    /// The visible view controller from a given view controller
    var visibleViewController: UIViewController? {
        if let navigationController = self as? UINavigationController {
            return navigationController.topViewController?.visibleViewController
        } else if let tabBarController = self as? UITabBarController {
            return tabBarController.selectedViewController?.visibleViewController
        } else if let presentedViewController = presentedViewController {
            return presentedViewController.visibleViewController
        } else if self is UIAlertController {
            return nil
        } else {
            return self
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Und*_*ndo 7

您可以在app delegate中实现此代码:

AppDelegate.m

-(void)presentViewControllerFromVisibleController:(UIViewController *)toPresent
{
    UIViewController *vc = self.window.rootViewController;
    [vc presentViewController:toPresent animated:YES];
}
Run Code Online (Sandbox Code Playgroud)

AppDelegate.h

-(void)presentViewControllerFromVisibleViewController:(UIViewController *)toPresent;
Run Code Online (Sandbox Code Playgroud)

来自哪里

#import "AppDelegate.h"
...
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
[delegate presentViewControllerFromVisibleViewController:myViewControllerToPresent];
Run Code Online (Sandbox Code Playgroud)

在你的代表中,你得到的rootViewControllerwindow.这将永远是可见的 - 它是一切的"父"控制者.

  • 我认为这通常会起作用,但根视图控制器始终可见是不正确的.屏幕上可能有一个模态视图控制器,我不确定如果在这种情况下运行此代码会发生什么. (7认同)
  • 是的,它仍然是根,但它不起作用 - 如果模式视图控制器在屏幕上,并且您尝试从根vc呈现另一个,则会收到警告,并且不会显示控制器(尝试present ... on <ViewController:>其视图不在窗口层次结构中!). (4认同)