2013-04-12 3 views
18

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

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

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

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

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

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

+0

вы используете раскадровки? –

+0

@SpaceDust nope – nebs

ответ

27

Ну, вы можете следить за цепью.

Начало работы [UIApplication sharedApplication].delegate.window.rootViewController.

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

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

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

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

+3

Это самый правильный ответ. –

+1

Я создал рекурсивный метод, используя вашу идею: https://gist.github.com/MartinMoizard/6537467. Работает как шарм :) – MartinMoizard

+0

Это правильный ответ. –

7

Вы могли бы этот код реализован в делегат своего приложения:

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]; 

В своем делегате вы получаете rootViewControllerwindow. Это всегда будет видно - это «родительский» контроллер всего.

+7

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

+0

@rdelmar В этом случае ваш корневой VC по-прежнему будет корнем, который представляет модальный VC. – Undo

+4

Да, это все еще корень, но он не сработает - если на экране установлен контроллер модального просмотра, и вы пытаетесь представить еще один из корневого vc, вы получите предупреждение, и контроллер не будет представлен (попытка для представления ... на , чей вид не находится в иерархии окон!). – rdelmar

2

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

файл интерфейса: MyModalViewController.h

#import <UIKit/UIKit.h> 

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

файл Реализация: MyModalViewController.м

#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 
19

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

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

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 дело вернуть ноль, если 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 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^