表示されているViewControllerビューが何であるかを知らなくても、View Controllerをモーダルに表示する方法はありますか?基本的には、任意の時点でアラートビューを表示するようなものです。
私は次のようなことができるようになりたいです:
MyViewController *myVC = [[MyViewController alloc] init];
[myVC showModally];
アプリのどこからでもこれを呼び出して、一番上に表示できるようにしたいと思います。現在のViewControllerが何であるかは気にしたくありません。
これを使用してログインプロンプトを表示する予定です。アラートビューを使用したくありません。また、アプリ全体でログインプレゼンテーションコードを使用したくありません。
これについて何か考えはありますか?それとも、これを達成するためのより良い方法はありますか?独自のメカニズムを実装して、ウィンドウの上にビューを配置する必要がありますか?
さて、あなたはチェーンをたどることができます。
_[UIApplication sharedApplication].delegate.window.rootViewController
_から開始します。
各ViewControllerで、次の一連のテストを実行します。
_[viewController isKindOfClass:[UINavigationController class]]
_の場合は、[(UINavigationController *)viewController topViewController]
に進みます。
_[viewController isKindOfClass:[UITabBarController class]]
_の場合は、[(UITabBarController *)viewController selectedViewController]
に進みます。
_[viewController presentedViewController]
_の場合は、_[viewController presentedViewController]
_に進みます。
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)
}
}
}
このソリューションは、最上位のView Controllerを提供するため、提示する前に特別な条件を処理できます。たとえば、最上位のViewControllerが特定のViewControllerでない場合にのみ、ViewControllerを表示したい場合があります。
_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
}
}
}
_
これにより、最上位のView Controllerが何であるかを知らなくても、どこからでもViewControllerを提示できます。
_UIApplication.topMostViewController?.present(viewController, animated: true, completion: nil)
_
または、最上位のViewControllerが特定のViewControllerでない場合にのみ、ViewControllerを提示します
_if let topVC = UIApplication.topMostViewController, !(topVC is FullScreenAlertVC) {
topVC.present(viewController, animated: true, completion: nil)
}
_
注意すべき点の1つは、現在表示されている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
}
}
}
_
このコードをアプリデリゲートに実装することができます。
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
を取得しています。これは常に表示されます-それはすべての「親」コントローラーです。
どのViewControllerが表示されているかを必ずしも知る必要はないと思います。アプリケーションの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