ViewController가 모달로 표시되는지 여부를 확인할 수 있습니까?


답변:


96

modalViewControlleriOS 6에서 더 이상 사용되지 않기 때문에 다음 은 iOS 5 이상에서 작동하고 경고없이 컴파일되는 버전입니다.

목표 -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
}

Felipe의 대답에 대한 모자 팁.


2
좋은 캐치, 오랜만에 다시 사용해야했고 지원 중단이 발생했음을 알았습니다. 사람들이 iOS 6 이상을 사용할 때 올바른 코드를 찾기 시작하도록 내 답변을 편집했습니다. 감사합니다
Felipe Sabino

10
부모 뷰 컨트롤러가 뷰 컨트롤러가 푸시되는 모달이면 작동하지 않습니다.
의미-문제

2
버그가 있습니다. 양쪽 모두 nil인지 확인해야합니다. 왜냐하면 nil == nilreturns YES이고 우리가 원하는 결과가 아니기 때문 입니다.
CocoaBob

1
@GabrielePetronella 메서드의 Swift 구현도 포함하도록 답변을 업데이트해도 될까요?
Michael Waterfall

1
@MichaelWaterfall 감사합니다. 감사합니다
Gabriele Petronella

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를 모달로 제시했습니다.

편집 2 : 더 이상 UIViewController대답하지 않고 대신 iOS 5 이상 확인을 추가 했습니다.parentViewControllerpresentingViewController

편집 3 : https://gist.github.com/3174081의 경우를 대비하여 요점을 만들었습니다.


modalViewController속성은 iOS 6부터 더 이상 사용되지 않습니다. 설명서에서는 presentedViewController대신 사용하도록 제안합니다 .
Bart Jacobs

@BartJacobs 좋은 지적! iOS6 출시 후이 답변을 보지 않았으므로 최신 정보가 아닐 수 있습니다. 나는 그것을 업데이트하기 위해 주 후반에 몇 가지 테스트를 시도 할 것입니다, tks!
Felipe Sabino

NSLog(@"%@", self.navigationController.parentViewController)지문 (null)-이유를 설명해 주시겠습니까? My ViewController는 스토리 보드의 navController를 통해 모달 뷰 컨트롤러와 연결됩니다.
Roman

@oyatek pastebin 또는 이와 유사한 것을 사용하여 코드를 보여줄 수 있습니까?
Felipe Sabino 2014

@Feilpe 문제를 발견했습니다- .parentViewController더 이상 사용되지 않으며 .presentingViewController대신 사용해야합니다.
Roman

35

iOS5 +에서 볼 수 있듯이 UIViewController Class Reference "presentingViewController"속성에서 가져올 수 있습니다.

presentingViewController이 뷰 컨트롤러를 제공 한 뷰 컨트롤러입니다. (읽기 전용)

@property (nonatomic, readonly) UIViewController * presentingViewController
토론

이 메시지를 수신 한 뷰 컨트롤러가 다른 뷰 컨트롤러에서 제공되는 경우이 속성은이를 제공하는 뷰 컨트롤러를 보유합니다. 뷰 컨트롤러가 표시되지 않았지만 상위 항목 중 하나가 표시되는 경우이 속성은 가장 가까운 상위 항목을 표시하는 뷰 컨트롤러를 보유합니다. 뷰 컨트롤러 나 그 조상이 표시되지 않는 경우이 속성은 nil을 유지합니다.

가용성
아이폰 OS 5.0 이상에서 사용할 수 있습니다. UIViewController.h에서
선언


3
완벽하게 작동합니다. if (self.presentingViewController) {// This is a modal viewContoller} else {// This is a normal ViewController}
mashdup

2
IMHO, 이것이 유일한 정답입니다. 단지의 존재를 확인 presentingViewController. 자동으로 조상을 순회하므로 컨테이너 뷰 컨트롤러에서도 작동합니다.
Daniel Rinser 2013

17

없는 경우 presentedAsModalUIViewController 하위 클래스 에서이 ( )에 대한 속성을 정의 YES하고 ViewController를 모달보기로 표시 하기 전에로 설정할 수 있습니다.

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

viewWillAppear재정의 에서이 값을 확인할 수 있습니다.

나는 견해가 어떻게 제시되는지를 명시하는 공식적인 재산이 없다고 생각하지만, 당신이 자신의 견해를 만드는 것을 방해하는 것은 없습니다.


RIght 그리고 이것은 내가 한 일이지만 다른 깔끔한 솔루션을 찾고있었습니다. 감사.
lukewar

UINavigationController속성을 추가하기 위해 사용자 지정 탐색 컨트롤러를 만들지 않는 한 모달로 표시하는 경우이 솔루션이 작동하지 않습니다 . 그런 다음 컨트롤러 내부에서 컨트롤러 self.navigationController가 모달로 표시되는지 확인해야 할 때마다이 사용자 지정 클래스 로 계속 캐스팅 해야합니다
Felipe Sabino 2011

8

self.navigationController가 모달로 표시되지만 self가 self.navigationController.viewControllers [0]과 같지 않은 경우 Petronella의 대답 은 작동하지 않습니다.이 경우 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 ins nil :(.
lukewar

'self.parentViewController'만 받으면 올바른 부모 개체를 반환합니까?
kubi

4
문제는 UIViewController 하위 클래스가 UINavigationController 또는 UITabBarController (또는 둘 다) 내에 있다는 것일 수 있습니다.이 경우 모달보기 컨트롤러로 제공된 부모를 찾기 위해보기 계층 구조를 조금 더 파헤쳐 야 할 수 있습니다.
hpique

@hgpc 내 프로젝트에서이 chck가 필요했기 때문에 UINavigationControllerUITabBarController사례 를 확인하기 위해 답변을 추가했습니다 . 지금까지 꽤 잘 작동하고 있습니다
Felipe Sabino

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

1
첫 번째 if 문은 두 번째 if 문에있는 모든 것을 다루며 두 번째 문을 중복으로 렌더링합니다. 의도가 무엇인지 모르겠습니다.
isoiphone 2016-07-15

1

내 프로젝트에는 모달로 (새 항목을 추가 할 때) 또는 푸시 (기존 항목을 편집 할 때)로 마스터 뷰 컨트롤러에 의해 표시 될 수있는 뷰 컨트롤러 (Detail)가 있습니다. 사용자가 [Done]을 탭하면 Detail view controller는 Master view controller의 메서드를 호출하여 닫을 준비가되었음을 알립니다. 마스터는 닫는 방법을 알기 위해 Detail이 표시되는 방법을 결정해야합니다. 이것은 내가 이것을하는 방법입니다.

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

다음은 @GabrielePetronella의 수정 된 버전입니다.이 버전은 isModal먼저 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.