Подтвердить что ты не робот

Представление модального контроллера, не зная текущего контроллера?

Есть ли способ представить контроллер вида, не зная, что такое вид видимого вида контроллера? В принципе, вроде бы вы показывали предупреждение в любой момент времени.

Я хотел бы сделать что-то вроде:

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

Я хотел бы иметь возможность называть это из любого места приложения и иметь его сверху. Я не хочу заботиться о том, что такое текущий контроллер.

Я планирую использовать это, чтобы показать приглашение для входа. Я не хочу использовать представление предупреждения, и я также не хочу иметь код представления входа во всем приложении.

Любые мысли об этом? Или, может быть, лучший способ добиться этого? Должен ли я просто реализовать свой собственный механизм и просто поместить представление поверх окна?

4b9b3361

Ответ 1

Ну, вы можете следовать цепочке.

Начните с [UIApplication sharedApplication].delegate.window.rootViewController.

На каждом контроллере представления выполните следующую последовательность тестов.

Если [viewController isKindOfClass:[UINavigationController class]], перейдите к [(UINavigationController *)viewController topViewController].

Если [viewController isKindOfClass:[UITabBarController class]], перейдите к [(UITabBarController *)viewController selectedViewController].

Если [viewController presentedViewController], перейдите к [viewController presentedViewController].

Ответ 2

Мое решение в 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)
        }
    }
}

Ответ 3

Этот код можно реализовать в делетете приложения:

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 window. Это всегда будет видно - это "родительский" контроллер всего.

Ответ 4

Это решение дает вам самый популярный контроллер, чтобы вы могли справиться с любыми особыми условиями перед его представлением. Например, возможно, вы хотите представить свой контроллер просмотра только в том случае, если контроллер верхнего уровня не является определенным контроллером представления.

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
        }
    }
}

С помощью этого вы можете представить свой контроллер просмотра из любой точки мира, не зная, что находится в верхней части контроллера.

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

Или представите свой контроллер просмотра только в том случае, если контроллер верхнего уровня не является определенным контроллером представления.

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

Следует отметить, что если в настоящее время отображается UIAlertController, UIApplication.topMostViewController вернет UIAlertController. Представление поверх UIAlertController имеет странное поведение и его следует избегать. Таким образом, вы должны либо вручную проверить, что !(UIApplication.topMostViewController is UIAlertController) перед представлением, либо добавить случай else if для возврата nil, если 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
        }
    }
}

Ответ 5

Я не думаю, что вам обязательно нужно знать, какой контроллер просмотра виден. Вы можете перейти к 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 view.
    [window addSubview: self.view];
}

@end