ビューコントローラーがモーダルに表示されているか、ナビゲーションスタックにプッシュされているかを確認するにはどうすればよいですか?


126

ビューコントローラーのコードで、次の違いをどのように区別できますか?

  • モーダルで提示された
  • ナビゲーションスタックにプッシュ

どちらpresentingViewControllerisMovingToParentViewControllerされているYES両方のケースでは、とても便利ではありません。

状況を複雑にしているのは、私の親のビューコントローラーが時々モーダルであり、その上にチェック対象のビューコントローラーがプッシュされることです。

私の問題は、私が私のHtmlViewController中に埋め込むことであり、UINavigationControllerそれが次に提示されることです。それが、私自身の試みと以下の良い答えがうまくいかなかった理由です。

HtmlViewController*     termsViewController = [[HtmlViewController alloc] initWithDictionary:dictionary];
UINavigationController* modalViewController;

modalViewController = [[UINavigationController alloc] initWithRootViewController:termsViewController];
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:modalViewController
                   animated:YES
                 completion:nil];

ビューコントローラーがモーダルであるかどうかを判断するのではなく、判断する方がいいと思います。

回答:


125

塩の粒を持って、テストしませんでした。

- (BOOL)isModal {
     if([self presentingViewController])
         return YES;
     if([[[self navigationController] presentingViewController] presentedViewController] == [self navigationController])
         return YES;
     if([[[self tabBarController] presentingViewController] isKindOfClass:[UITabBarController class]])
         return YES;

    return NO;
 }

12
私はこれを別のSOの投稿で見つけました。ただし、プッシュされたビューコントローラーの親がモーダルの場合は機能しません。これが私の状況です。
意味の問題

2
私が書いたように、presentingViewController常にYES私の場合です。助けにならない。
意味の問題

3
presentingViewControllerルートとして設定されているYESがある場合、プッシュされたVCに戻りますUITabBarController。だから、私の場合には適していません。
Yevhen Dubinin 2014年

5
これは、ビューコントローラーを提示してから別のコントローラーをプッシュする場合は機能しません。
リー

3
「ビューコントローラーを提示すると、これは機能せず、別のビューコントローラーをプッシュします」これは意図ではなく、プッシュされたビューコントローラーが提示されていません。
コリン・スウェリン2017年

87

ではスウィフト

フラグを追加して、クラスタイプによってモーダルかどうかをテストします。

// MARK: - UIViewController implementation

extension UIViewController {

    var isModal: Bool {

        let presentingIsModal = presentingViewController != nil
        let presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController
        let presentingIsTabBar = tabBarController?.presentingViewController is UITabBarController

        return presentingIsModal || presentingIsNavigation || presentingIsTabBar
    }
}

4
次のように、var isModal: Bool {}
変数の

1
@malinoisが変更されました
YannSteph 2018年

ステートメントの最後のfalseパラメーターは何をしreturnますか?
damjandd

presentingIsNavigation = navigationController?.presentingViewController?.presentedViewController == navigationController && navigationController!= nil
famfamfam

78

1つのメソッドを見落としました:isBeingPresented

isBeingPresented ビューコントローラーが提示されている場合はtrue、プッシュされている場合はfalseです。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if ([self isBeingPresented]) {
        // being presented
    } else if ([self isMovingToParentViewController]) {
        // being pushed
    } else {
        // simply showing again because another VC was dismissed
    }
}

2
私も投稿前にこれを試みたが、それは動作しません、isBeingPresentedですNO。しかし、今は理由がわかります。提示したView Controllerをに埋め込んでいUINavigationControllerます。それが私が推進しているものです。
意味の問題

1
ナビゲーションコントローラをプッシュすることはできません。多分あなたはあなたがナビゲーションコントローラーを提示していることを意味しました。
rmaddy

3
@jowie プリミティブ値を出力するときpではなくpo、を使用します。poオブジェクトを印刷するためのものです。
rmaddy 2015年

37
ドキュメンテーションisBeingPresented-このメソッドは、viewWillAppear:およびviewDidAppear:メソッド内から呼び出された場合にのみYESを返します。
funct7

4
@Terrence最新のドキュメントにはその情報は示されていませんが、以前はそこにあったようです。isBeingPresentedisBeingDismissedisMovingFromParentViewControllerおよびisMovingToParentViewController4つの内側にのみ有効ですview[Will|Did][Disa|A]ppear方法。
rmaddy 2017年

29

Swift 5
これは、提示されたスタックにプッシュされた場合にisModal()戻るときに、以前の回答で言及された問題に対処するソリューションです。trueUIViewControllerUINavigationController

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if navigationController?.presentingViewController?.presentedViewController == navigationController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

これまでのところ、うまくいきます。いくつかの最適化がある場合は、共有してください。


なぜ確認する必要があるのtabBarController?.presentingViewController is UITabBarController ですか?それがpresentingViewControllerUITabBarControllerでもあるかどうかは重要ですか?
フルン

そして、navigationControllerがnilの場合、isModalを返しtrueます。これは意図されていますか?
Hlung

28

self.navigationController!= nilは、ナビゲーションスタックにあることを意味します。

ナビゲーションコントローラーがモーダルで表示されているときに現在のビューコントローラーがプッシュされるケースを処理するために、現在のビューコントローラーがナビゲーションスタックのルートコントローラーであるかどうかを確認するコード行を追加しました。

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            return true
        } else if let navigationController = navigationController, navigationController.presentingViewController?.presentedViewController == navigationController {
            return true
        } else if let tabBarController = tabBarController, tabBarController.presentingViewController is UITabBarController {
            return true
        } else {
            return false
        }
    }
}

一般的に、モーダルで表示する場合は、viewControllerをnavigationControllerに配置して表示します。その場合、ステートメントは間違っていますが、コードではこのケースが処理されます。答えを改善してください:)
E-Riddie 2017

すべてのユースケースを扱う良い仕事。おそらく少しリファクタリングする余地がありますが、それでも賛成投票してください!!
Jean Raymond Daher、

12

スウィフト4

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

Swift 4.2 / iOS 12.引き続き正常に動作しますが、navigationController?.presentingViewController?.presentedViewController === navigationControllerは、両方がnilの場合(たとえば、まだコントローラーになっていないビューコントローラーで呼び出す場合)にtrueと評価されることに注意してください。提示)。
Eli Burke、

7

Swift 5.クリーンでシンプル。

if navigationController.presentingViewController != nil {
    // Navigation controller is being presented modally
}

1
これは私にとってはトリックでした
Radu Ursache

3

ここの多くの人々が提案するように、「チェック」方法はすべての場合にうまく機能しない、私のプロジェクトでは私はそれを手動で管理するためのソリューションを考え出しました。重要なのは、通常はプレゼンテーションを自分で管理することです。これは舞台裏で行われることではなく、内省する必要があります。

DEViewController.h ファイル:

#import <UIKit/UIKit.h>

// it is a base class for all view controllers within a project
@interface DEViewController : UIViewController 

// specify a way viewcontroller, is presented  by another viewcontroller
// the presented view controller should manually assign the value to it
typedef NS_ENUM(NSUInteger, SSViewControllerPresentationMethod) {
    SSViewControllerPresentationMethodUnspecified = 0,
    SSViewControllerPresentationMethodPush,
    SSViewControllerPresentationMethodModal,
};
@property (nonatomic) SSViewControllerPresentationMethod viewControllerPresentationMethod;

// other properties/methods...
@end

プレゼンテーションは次のように管理できます。

ナビゲーションスタックにプッシュ:

// DETestViewController inherits from DEViewController
DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodPush;
[self.navigationController pushViewController:vc animated:YES];

ナビゲーションをモーダルで提示:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
UINavigationController *nav = [[UINavigationController alloc]
                               initWithRootViewController:vc];
[self presentViewController:nav animated:YES completion:nil];

モーダルで提示:

DETestViewController *vc = [DETestViewController new];
vc.viewControllerPresentationMethod = SSViewControllerPresentationMethodModal;
[self presentViewController:vc animated:YES completion:nil];

また、DEViewController前述のプロパティが以下と等しい場合、「チェック」にフォールバックを追加できますSSViewControllerPresentationMethodUnspecified

- (BOOL)isViewControllerPushed
{
    if (self.viewControllerPresentationMethod != SSViewControllerPresentationMethodUnspecified) {
        return (BOOL)(self.viewControllerPresentationMethod == SSViewControllerPresentationMethodPush);
    }

    else {
        // fallback to default determination method
        return (BOOL)self.navigationController.viewControllers.count > 1;
    }
}

3

モーダルで提示するすべてのviewControllerが新しいnavigationController(常に行う必要がある)内にラップされていると仮定すると、このプロパティをVCに追加できます。

private var wasPushed: Bool {
    guard let vc = navigationController?.viewControllers.first where vc == self else {
        return true
    }

    return false
}

1
とにかくいつもすべきこと -理由を教えてください
Alexander Abakumov

アレクサンダー、そうすべきではありません。
nickdnk 2018年

2

コントローラがプッシュされたことを検出するには、必要な場所で以下のコードを使用するだけではありません。

if ([[[self.parentViewController childViewControllers] firstObject] isKindOfClass:[self class]]) {

    // Not pushed
}
else {

    // Pushed
}

このコードが誰にも役立つことを願っています...


1
このメソッドは、そのクラスのみをチェックするため、同じビューコントローラクラスを複数の場所で使用する場合は機能しません。代わりに、等価性を明示的に確認できます。
gklka

1

self.navigationController != nil ナビゲーションスタックにあることを意味します。


25
まだモーダルナビゲーションコントローラーにあることができます
ColdLogic 2014年

したがって、「モーダル」と「プッシュされたナビゲーションスタック」は相互に排他的ではありません。これを考えるのはコンテキストに依存しますが、self.navigationControllerがnilでないかどうかを確認すると、それがナビゲーションコントローラーのビューコントローラーであるかどうかがわかります。
ダニエル

@Daniel「プッシュ」と「提示」の違いです。「モーダル」はそれとは何の関係もありません。「モーダル」と言ったとき、「ColdLogic」は「提示された」という意味だったと
思い

1
if let navigationController = self.navigationController, navigationController.isBeingPresented {
    // being presented
}else{
    // being pushed
}

0

iOS 5.0以降を使用している場合は、このコードを使用してください

-(BOOL)isPresented
{
    if ([self isBeingPresented]) {
        // being presented
         return YES;
    } else if ([self isMovingToParentViewController]) {
        // being pushed
         return NO;
    } else {
        // simply showing again because another VC was dismissed
         return NO;
    }
}

0

Swift 5
この便利な拡張機能は、以前の回答よりもいくつかのケースを処理します。これらのケースはVC(ビューコントローラー)がアプリウィンドウのルートVCであり、VCは親VCの子として追加されます。ビューコントローラーがモーダルに提示されている場合にのみtrueを返そうとします。

extension UIViewController {
    /**
      returns true only if the viewcontroller is presented.
    */
    var isModal: Bool {
        if let index = navigationController?.viewControllers.firstIndex(of: self), index > 0 {
            return false
        } else if presentingViewController != nil {
            if let parent = parent, !(parent is UINavigationController || parent is UITabBarController) {
                return false
            }
            return true
        } else if let navController = navigationController, navController.presentingViewController?.presentedViewController == navController {
            return true
        } else if tabBarController?.presentingViewController is UITabBarController {
            return true
        }
        return false
    }
}

ジョナウズの回答に感謝します。繰り返しますが、より多くの最適化のためのスペースがあります。対処が必要なケースについてはコメント欄でご相談ください。


-1

不思議に思う人のために、ViewControllerに提示されていることを伝える方法

A提示/押している場合B

  1. 定義enumproperty中をB

    enum ViewPresentationStyle {
        case Push
        case Present
    }
    
    //and write property 
    
    var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
  2. Aビューコントローラーで、B割り当てによって表示/プッシュされているかどうかを確認しますpresentationStyle

    func presentBViewController() {
        let bViewController = B()
        bViewController.vcPresentationStyle = .Present //telling B that it is being presented
        self.presentViewController(bViewController, animated: true, completion: nil)
    }
  3. BView Controllerでの使用

    override func viewDidLoad() {
        super.viewDidLoad()
    
        if self.vcPresentationStyle == .Present {
            //is being presented 
        }
        else {
            //is being pushed
        }
    
    }

-2
id presentedController = self.navigationController.modalViewController;
if (presentedController) {
     // Some view is Presented
} else {
     // Some view is Pushed
}

これにより、viewControllerが表示またはプッシュされているかどうかがわかります


4
このプロパティは非推奨です。
Morkrom、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.