web-dev-qa-db-ja.com

ViewControllerがモーダルとして表示されるかどうかを判断することはできますか?

ViewControllerクラス内でモーダルView Controllerとして表示されていることを確認できますか?

115
lukewar

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
}

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

95

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


UIKit固有のプロパティまたはメソッドとして、これを行うための適切な方法はありません。できることは、コントローラーのいくつかの側面をチェックして、モーダルとして表示されることを確認することです。

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

-(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をモーダルとして提示します。

編集2:iOSの5+チェックを追加しました。ここで、UIViewControllerparentViewControllerに対しては応答せず、代わりにpresentingViewControllerに対して応答します。

編集3:念のためにGistを作成しました https://Gist.github.com/3174081

77
Felipe Sabino

IOS5 +では、 IViewController Class Reference でわかるように、プロパティ "presentingViewController"から取得できます。

presentingViewControllerこのView Controllerを表示したView Controller。 (読み取り専用)

@property(nonatomic、readonly)UIViewController * presentingViewController
討論

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

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

35
Raj

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

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

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

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

17
hpique

Petronella's answer 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
8
Semih Cihan

これは動作するはずです。

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

チェックする最良の方法

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

私のプロジェクト(フォームシートとページシートでのみ発生する問題を扱っていた)の場合、フルスクリーンモーダルビューと非モーダルビューを区別する必要がない場合は、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
arlomedia

In Swift

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
}
2
King-Wizard

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

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

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

// 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
mixtly87

これは、@ GabrielePetronellaの isModal の修正バージョンです。これは、最初にparentViewController階層を上るという点で、含まれるView Controllerで動作します。また、コードを複数行に引き出して、コードが何をしているのかを明確にします。

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

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

- (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
DennyLou

このようなハックが機能する可能性があります。

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
hpique