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

时间:2013-04-12 00:45:05

标签: ios modal-dialog presentmodalviewcontroller

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

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

MyViewController *myVC = [[MyViewController alloc] init];
[myVC showModally];

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

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

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

5 个答案:

答案 0 :(得分:29)

好吧,你可以关注链条。

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

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

如果[viewController isKindOfClass:[UINavigationController class]],请转到[(UINavigationController *)viewController topViewController]

如果[viewController isKindOfClass:[UITabBarController class]],请转到[(UITabBarController *)viewController selectedViewController]

如果[viewController presentedViewController],请转到[viewController presentedViewController]

答案 1 :(得分: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)
        }
    }
}

答案 2 :(得分:8)

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

UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)

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

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

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

UIApplication.topMostViewController

需要注意的一点是,如果当前正在显示UIAlertController,UIAlertController将返回UIAlertController。在!(UIApplication.topMostViewController is UIAlertController)之上呈现有奇怪的行为,应该避免。因此,您应该在展示之前手动检查else if,或者添加self 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 } } }

,则返回nil
var reply = context.MakeMessage();
var card = new AdaptiveCard();

var choices = new List<Choice>();
choices.Add(new Choice()
{
    Title = "Category 1",
    Value = "c1"
});
choices.Add(new Choice()
{
    Title = "Category 2",
    Value = "c2"                       
});
var choiceSet = new ChoiceSet()
{
    IsMultiSelect = false,
    Choices = choices,
    Style = ChoiceInputStyle.Compact,
    Id = "Category"
};
card.Body.Add(choiceSet);
card.Actions.Add(new SubmitAction() { Title = "Select Category", Data = Newtonsoft.Json.Linq.JObject.FromObject(new { button = "select" }) });

reply.Attachments.Add(new Attachment()
{
    Content = card,
    ContentType = AdaptiveCard.ContentType, 
    Name = $"Card"
});

await context.PostAsync(reply);

答案 3 :(得分:7)

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

<强> AppDelegate.m

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

<强> AppDelegate.h

-(void)presentViewControllerFromVisibleViewController:(UIViewController *)toPresent;

从哪里

#import "AppDelegate.h"
...
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
[delegate presentViewControllerFromVisibleViewController:myViewControllerToPresent];

在您的代表中,您获得了rootViewController的{​​{1}}。这将永远是可见的 - 它是一切的“父母”控制者。

答案 4 :(得分:2)

我认为你不一定需要知道哪个视图控制器是可见的。您可以转到应用程序的keyWindow,并将模态视图控制器的视图添加到视图列表的顶部。然后,您可以使其像UIAlertView一样工作。

接口文件: MyModalViewController.h

#import <UIKit/UIKit.h>

@interface MyModalViewController : UIViewController
- (void) show;
@end

实施文件: MyModalViewController.m

#import "MyModalViewController.h"


@implementation MyModalViewController

- (void) show {
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    //  Configure the frame of your modal's view.
    [window addSubview: self.view];
}

@end