ViewControllerがモーダルとして提示されているかどうかを判断することは可能ですか?


117

モーダルビューコントローラーとして表示されていることをViewControllerクラス内で確認することはできますか?

回答:


96

以来modalViewControllerのiOS 6で廃止されました、ここで警告なしのiOS 5+とそのコンパイルのために働くのバージョンがあります。

Objective-C:

- (BOOL)isModal {
    return self.presentingViewController.presentedViewController == self
      || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController)
      || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];
}

迅速:

var isModal: Bool {
    return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController)
        || self.tabBarController?.presentingViewController is UITabBarController
}

フェリペの答えへの帽子のヒント。


2
良いキャッチ、私は久しぶりにもう一度それを使用する必要があり、非推奨が発生したことに気づきました... iOS 6+を使用しているときに人々が正しいコードをここで探し始めるように私の回答を編集しました、ありがとう
Felipe Sabino

10
親のビューコントローラーが、ビューコントローラーがプッシュされるモーダルの場合は機能しません。
意味に関する事項

2
バグがありnil == nilます。が返されるため、両側がnilであるかどうかを確認する必要がありますが、これは目的YESの結果ではありません。
CocoaBob 2015

1
@GabrielePetronellaメソッドのSwift実装も含めるように回答を更新してもよろしいですか?
マイケルウォーターフォール、

1
@MichaelWaterfall感謝します。ありがとう
ガブリエレペトロ

77

iOS 6以降をお探しの場合、この回答は非推奨であり、Gabriele Petronellaの回答を確認する必要があります


UIKitにネイティブなプロパティまたはメソッドとして、これを行うためのきちんとした方法はありません。あなたができることは、それがモーダルとして提示されることを確実にするために、コントローラーのいくつかの側面をチェックすることです。

したがって、現在の(以下selfのコードのように表される)コントローラーがモーダルな方法で表示されているかUIViewControllerどうかを確認するには、カテゴリー内に以下の関数を持っているか、または(プロジェクトで他のUIKitコントローラーを使用する必要がない場合は、UITableViewControllerたとえば、他のコントローラーが継承する基本コントローラー

-(BOOL)isModal {

     BOOL isModal = ((self.parentViewController && self.parentViewController.modalViewController == self) || 
            //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
            ( self.navigationController && self.navigationController.parentViewController && self.navigationController.parentViewController.modalViewController == self.navigationController) || 
            //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
            [[[self tabBarController] parentViewController] isKindOfClass:[UITabBarController class]]);

    //iOS 5+
    if (!isModal && [self respondsToSelector:@selector(presentingViewController)]) {

        isModal = ((self.presentingViewController && self.presentingViewController.modalViewController == self) || 
             //or if I have a navigation controller, check if its parent modal view controller is self navigation controller
             (self.navigationController && self.navigationController.presentingViewController && self.navigationController.presentingViewController.modalViewController == self.navigationController) || 
             //or if the parent of my UITabBarController is also a UITabBarController class, then there is no way to do that, except by using a modal presentation
             [[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]]);

    }

    return isModal;        

}

編集:UITabBarControllerが使用されているかどうかを確認する最後のチェックを追加し、別のUITabBarControllerをモーダルとして提示しました。

EDIT 2:iOSの5+チェック、追加UIViewControllerのためにお答えいたしませんparentViewControllerもうし、これにpresentingViewController代わり。

編集3:念のためhttps://gist.github.com/3174081で要点を作成しました


ことを覚えておいてくださいmodalViewControllerドキュメントが使用することを示唆しているのiOS 6のようプロパティが廃止されてpresentedViewController代わりに。
バートジェイコブス

@BartJacobs良い点!iOS6のリリース後、私はこの回答を見ていません。そのため、最新ではない可能性があります。私はそれを更新するために週の後半にいくつかのテストをしようとするでしょう、tks!
フェリペサビノ

NSLog(@"%@", self.navigationController.parentViewController)版画(null)-理由を教えてください。私のViewControllerは、ストーリーボードのnavControllerを介してモーダルビューコントローラーに接続されています。
ローマ

@oyatekあなたはペーストビンまたは類似の何かを使用していくつかのコードを表示できますか?
フェリペサビノ2014

@Feilpe問題を見つけました- .parentViewController非推奨です.presentingViewController。代わりに使用する必要があります。
ローマ

35

iOS5以降では、UIViewController Class Referenceでわかるように、プロパティ「presentingViewController」から取得できます。

presentingViewControllerこのビューコントローラを提示したビューコントローラ。(読み取り専用)

@property(nonatomic、readonly)UIViewController * presentingViewController
ディスカッション

このメッセージを受け取ったビューコントローラーが別のビューコントローラーによって提示された場合、このプロパティはそれを提示しているビューコントローラーを保持します。ビューコントローラーは表示されないが、その祖先の1つが表示されている場合、このプロパティは最も近い祖先を表示するビューコントローラーを保持します。ビューコントローラーもその祖先も表示されていない場合、このプロパティはnilを保持します。

可用性
のiOS 5.0以降で利用可能。
宣言
UIViewController.hで


3
完全に機能し、if(self.presentingViewController)を使用します{//これはモーダルのviewContollerです。それ以外の場合{//これは通常のViewControllerです}}
mashdup

2
私見、これがここでの唯一の正しい答えです。の存在を確認するだけpresentingViewControllerです。祖先を自動的にトラバースするため、コンテナビューコントローラでも機能します。
Daniel Rinser

17

ない場合はpresentedAsModal、UIViewControllerサブクラスでthis()のプロパティを定義YESし、ViewControllerをモーダルビューとして表示する前に設定できます。

childVC.presentedAsModal = YES;
[parentVC presentModalViewController:childVC animated:YES];

この値はviewWillAppearオーバーライドで確認できます。

ビューの表示方法を示す公式のプロパティは存在しないと思いますが、独自のビューを作成することを妨げるものは何もありません。


これは私がやったことですが、他のきちんとした解決策を探していました。ありがとう。
lukewar

UINavigationControllerモーダルとして表示している場合、このソリューションは機能しません...このプロパティを追加するためだけにカスタムナビゲーションコントローラーを作成する場合を除きます。その後、コントローラー内ではself.navigationController、コントローラーがモーダルとして表示されているかどうかを確認する必要があるたびに、このカスタムクラスにキャストし続ける必要があります
Felipe Sabino

8

self.navigationControllerがモーダルに提示されているが、selfがself.navigationController.viewControllers [0]と等しくない場合、ペトロネラの答えは機能しません。その場合、selfがプッシュされます。

これが問題を修正する方法です。

return self.presentingViewController.presentedViewController == self
            || (self.navigationController != nil && self.navigationController.presentingViewController.presentedViewController == self.navigationController && self == self.navigationController.viewControllers[0])
            || [self.tabBarController.presentingViewController isKindOfClass:[UITabBarController class]];

そしてSwiftでは:

return self.presentingViewController?.presentedViewController == self
        || (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController && self.navigationController?.viewControllers[0] == self)
        || self.tabBarController?.presentingViewController is UITabBarController

6

これはうまくいくはずです。

if(self.parentViewController.modalViewController == self)…

残念ながら、これは機能しません。初めての試みでした。しかしmodalViewControllerインゼロ:(返さ。
lukewar

「self.parentViewController」だけを取得した場合、正しい親オブジェクトが返されますか?
kubi

4
問題は、UIViewControllerサブクラスがUINavigationControllerまたはUITabBarController(またはその両方)内にあることである可能性があります。その場合、モーダルビューコントローラーとして提示された親を見つけるために、ビュー階層をもう少し掘る必要がある場合があります。
hpique 2010年

@hgpcプロジェクトでこのチェックが必要だったので、両方UINavigationControllerUITabBarControllerケースを確認するための回答を追加しました。これまでのところ、順調に機能しています
フェリペサビノ

4

チェックする最良の方法

 if (self.navigationController.presentingViewController) {
         NSLog(@"Model Present");
    }

2

全画面のモーダルビューと非モーダルビューを区別する必要がない場合(私のプロジェクトの場合(フォームシートとページシートでのみ発生する問題を扱っていました))、modalPresentationStyleを使用できます。 UIViewControllerのプロパティ:

switch (self.modalPresentationStyle) {
    case 0: NSLog(@"full screen, or not modal"); break;
    case 1: NSLog(@"page sheet"); break;
    case 2: NSLog(@"form sheet"); break;
}

2

ではスウィフト

func isUIViewControllerPresentedAsModal() -> Bool {
    if((self.presentingViewController) != nil) {
        return true
    }

    if(self.presentingViewController?.presentedViewController == self) {
        return true
    }

    if(self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) {
        return true
    }

    if((self.tabBarController?.presentingViewController?.isKindOfClass(UITabBarController)) != nil) {
        return true
    }

    return false
}

この使用例には問題があります。UINavigationControllerのルートビューコントローラーにいる場合でも、モーダルプレゼンテーションがなくてもtrueを返します。
mariusLAN 2015年

1
最初のifステートメントは、2番目のifステートメントのすべてをカバーし、2番目のステートメントを冗長にします。ここに何の意図があるのか​​わかりません。
isoiphone

1

私のプロジェクトには、マスタービューコントローラーによってモーダル(新しいアイテムを追加する場合)またはプッシュ(既存のアイテムを編集する場合)で表示できるビューコントローラー(詳細)があります。ユーザーが[完了]をタップすると、詳細ビ​​ューコントローラーはマスタービューコントローラーのメソッドを呼び出して、閉じる準備ができたことを通知します。マスターは、それを閉じる方法を知るために、詳細がどのように提示されるかを決定する必要があります。これは私がこれを行う方法です:

UIViewController *vc = self.navigationController.viewControllers.lastObject;
if (vc == self) {
    [self dismissViewControllerAnimated:YES completion:NULL];
} else {
    [self.navigationController popViewControllerAnimated:YES];
}

0

このようなハックはうまくいくかもしれません。

UIViewController* child = self;
UIViewController* parent = child.parentViewController;
while (parent && parent.modalViewController != child) {
    child = parent;
    parent = child.parentViewController;
}
if (parent) {
    // A view controller in the hierarchy was presented as a modal view controller
}

しかし、私の以前の答えはより明確な解決策だと思います。


0

私のために働いたのは以下の通りです:

// this is the trick: set parent view controller as application's window root view controller
UIApplication.sharedApplication.delegate.window.rootViewController = viewController;

// assert no modal view is presented
XCTAssertNil(viewController.presentedViewController);

// simulate button tap which shows modal view controller
[viewController.deleteButton sendActionsForControlEvents:UIControlEventTouchUpInside];

// assert that modal view controller is presented
XCTAssertEqualObjects(viewController.presentedViewController.class, MyModalViewController.class);

私がテストした限り、これはiOS7とiOS8で動作します。ただし、iOS6は試しませんでした。


0

私はこの質問に対する正しい答えを見つけるために少し調べましたが、考えられるすべてのシナリオをカバーするものは見つかりませんでした。私は仕事をしているように見えるこれらの数行のコードを書きました。何がチェックされているかを理解するために、いくつかのインラインコメントを見つけることができます。

- (BOOL)isModal {
    BOOL modal = NO;
    if ([self presentingViewController]) { //Some view Controller is presenting the current stack
        UIViewController *presented = [[self presentingViewController] presentedViewController]; // What's been presented
        if ([presented respondsToSelector:@selector(viewControllers)]) { // There's a stack
            NSArray *viewControllers = [presented performSelector:@selector(viewControllers)];
            modal = [viewControllers firstObject] == self; // Current VC is presented modally if it's the first in the stack
        }
        else {
            modal = presented == self; // Don't think this is actually needed. set modal = YES should do the job tho.
        }
    }
    return modal;
}

この助けを願っています。


0

isModal@GabrielePetronellaの変更バージョンは次のとおりです。これは、最初にparentViewController階層を上に移動するという点で、含まれているビューコントローラーで動作します。また、コードを複数行に引き出して、何をしているのかを明確にしました。

var isModal: Bool {
    // If we are a child view controller, we need to check our parent's presentation
    // rather than our own.  So walk up the chain until we don't see any parentViewControllers
    var potentiallyPresentedViewController : UIViewController = self
    while (potentiallyPresentedViewController.parentViewController != nil) {
        potentiallyPresentedViewController = potentiallyPresentedViewController.parentViewController!
    }

    if self.presentingViewController?.presentedViewController == potentiallyPresentedViewController {
        return true
    }

    if let navigationController = potentiallyPresentedViewController.navigationController {
        if navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        }
    }

    return potentiallyPresentedViewController.tabBarController?.presentingViewController is UITabBarController
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.