Có thể xác định xem ViewController có được trình bày dưới dạng Modal không?


117

Có thể kiểm tra bên trong lớp ViewController rằng nó được trình bày dưới dạng bộ điều khiển chế độ xem phương thức không?

Câu trả lời:


96

modalViewControllerđã không được dùng nữa trong iOS 6, đây là phiên bản hoạt động cho iOS 5+ và biên dịch mà không có cảnh báo.

Mục tiêu-C:

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

Nhanh:

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

Lời khuyên cho câu trả lời của Felipe.


2
bắt tốt, tôi chỉ phải sử dụng lại sau một thời gian dài và nhận thấy rằng sự cố không dùng nữa đã xảy ra ... Tôi đã chỉnh sửa câu trả lời của mình để mọi người bắt đầu tìm mã chính xác khi sử dụng iOS 6+, cảm ơn
Felipe Sabino

10
Không hoạt động nếu bộ điều khiển chế độ xem chính là một phương thức mà bộ điều khiển chế độ xem của chúng tôi được đẩy vào.
ý nghĩa-vấn đề

2
Có một lỗi, chúng ta nên kiểm tra xem cả hai bên đều không, vì nil == niltrả về YESvà nó không phải là kết quả chúng ta muốn.
CocoaBob

1
@GabrielePetronella Bạn có phiền nếu tôi cập nhật câu trả lời để bao gồm triển khai Swift của phương thức này không?
Thác nước Michael

1
@MichaelWaterfall sẽ được đánh giá rất cao, cảm ơn
Gabriele Petronella

77

Nếu bạn đang tìm kiếm iOS 6+, câu trả lời này không được dùng nữa và bạn nên kiểm tra câu trả lời của Gabriele Petronella


Không có cách nào gọn gàng để làm điều đó, vì một thuộc tính hoặc phương thức có nguồn gốc từ UIKit. Những gì bạn có thể làm là kiểm tra một số khía cạnh của bộ điều khiển để đảm bảo nó được trình bày dưới dạng phương thức.

Vì vậy, để kiểm tra xem bộ điều khiển hiện tại (được biểu thị như selftrong mã bên dưới) có được trình bày theo cách thức hay không, tôi có chức năng bên dưới hoặc trong một UIViewControllerdanh mục hoặc (nếu dự án của bạn không cần sử dụng các bộ điều khiển UIKit khác, như UITableViewControllerví dụ) trong bộ điều khiển cơ sở mà các bộ điều khiển khác của tôi kế thừa

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

}

CHỈNH SỬA: Tôi đã thêm lần kiểm tra cuối cùng để xem liệu một UITabBarController có đang được sử dụng hay không và bạn trình bày một UITabBarController khác dưới dạng phương thức.

EDIT 2: đã thêm kiểm tra iOS 5+, nơi UIViewControllerkhông trả lời cho parentViewControllernữa mà presentingViewControllerthay vào đó.

CHỈNH SỬA 3: Tôi đã tạo ý chính cho nó chỉ trong trường hợp https://gist.github.com/3174081


Hãy nhớ rằng thuộc modalViewControllertính không được chấp nhận kể từ iOS 6. Tài liệu đề xuất sử dụng presentedViewControllerthay thế.
Bart Jacobs

@BartJacobs điểm tốt! Tôi chưa xem câu trả lời này sau khi phát hành iOS6, vì vậy nó có thể không được cập nhật. Cuối tuần mình sẽ cố gắng làm một số bài test để update lên, tks!
Felipe Sabino

NSLog(@"%@", self.navigationController.parentViewController)bản in (null)- bạn có thể vui lòng giải thích tại sao không? ViewController của tôi được kết nối với bộ điều khiển chế độ xem phương thức thông qua navController trong bảng phân cảnh.
Roman

@oyatek bạn có thể sử dụng pastebin hoặc thứ gì đó tương tự và hiển thị một số mã không?
Felipe Sabino

@Feilpe Tôi đã tìm thấy sự cố - .parentViewControllerkhông được dùng nữa, .presentingViewControllerphải được sử dụng thay thế.
Roman

35

Trong iOS5 +, Như bạn có thể thấy trong Tham chiếu lớp UIViewController , bạn có thể lấy nó từ thuộc tính "PresentationViewController".

PresentationViewController Bộ điều khiển chế độ xem đã trình bày bộ điều khiển chế độ xem này. (chỉ đọc)

@property (nonatomic, chỉ đọc) UIViewController * PresentationViewController
Discussion

Nếu bộ điều khiển dạng xem đã nhận được thông báo này được trình bày bởi bộ điều khiển dạng xem khác, thì thuộc tính này giữ bộ điều khiển dạng xem đang trình bày nó. Nếu bộ điều khiển chế độ xem không được trình bày, nhưng một trong những tổ tiên của nó đang được trình bày, thuộc tính này giữ bộ điều khiển chế độ xem trình bày tổ tiên gần nhất. Nếu không có bộ điều khiển chế độ xem hoặc bất kỳ tổ tiên nào của nó đang được hiển thị, thì thuộc tính này là nil.

Tính khả dụng
Có sẵn trong iOS 5.0 trở lên.
Được khai báo trong
UIViewController.h


3
Hoạt động hoàn hảo, hãy sử dụng if (self.presentingViewController) {// Đây là một phương thức viewContoller} else {// Đây là một ViewController bình thường}
mashdup

2
IMHO, đây là câu trả lời chính xác duy nhất ở đây. Chỉ cần kiểm tra sự hiện diện của a presentingViewController. Nó cũng sẽ hoạt động trong bộ điều khiển chế độ xem vùng chứa, vì nó tự động chuyển qua tổ tiên.
Daniel Rinser

17

Nếu không có, bạn có thể xác định một thuộc tính cho this ( presentedAsModal) trong lớp con UIViewController của bạn và đặt nó thành YEStrước khi trình bày ViewController dưới dạng một chế độ xem phương thức.

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

Bạn có thể kiểm tra giá trị này trong viewWillAppearghi đè của mình .

Tôi tin rằng không có thuộc tính chính thức nào cho biết cách hiển thị chế độ xem, nhưng không có gì ngăn cản bạn tạo chế độ xem của riêng mình.


Đúng và đây là những gì tôi đã làm nhưng tôi đang tìm kiếm một số giải pháp gọn gàng khác. Cảm ơn.
lukewar

giải pháp này không hoạt động nếu bạn đang trình bày UINavigationControllerdưới dạng phương thức ... trừ khi bạn tạo bộ điều khiển điều hướng tùy chỉnh chỉ để thêm thuộc tính này. Và sau đó, bên trong bộ điều khiển, bạn sẽ phải tiếp tục đúc self.navigationControllervào lớp tùy chỉnh này mỗi khi bạn cần phải kiểm tra nếu bộ điều khiển được trình bày như modal
Felipe Sabino

8

Câu trả lời của Petronella không hoạt động nếu self.navigationController được trình bày theo phương thức nhưng self không bằng self.navigationController.viewControllers [0], trong trường hợp đó, self được đẩy.

Đây là cách bạn có thể khắc phục sự cố.

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]];

Và trong 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

Điều này sẽ hoạt động.

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

Thật không may, điều này không hoạt động. Đó là lần thử đầu tiên của tôi. Nhưng modalViewController trả lại trong nil :(.
lukewar

Nếu bạn chỉ nhận được 'self.parentViewController', nó có trả về đúng đối tượng cha không?
kubi

4
Vấn đề có thể là lớp con UIViewController của bạn nằm bên trong UINavigationController hoặc UITabBarController (hoặc cả hai), trong trường hợp đó, bạn có thể cần tìm hiểu thêm một chút trong phân cấp chế độ xem để tìm ra lớp cha được trình bày dưới dạng bộ điều khiển chế độ xem phương thức.
hpique

@hgpc tôi cần chck này trong dự án của tôi, vì vậy tôi chỉ cần thêm một câu trả lời để kiểm tra cho cả hai UINavigationControllerUITabBarControllertrường hợp. Nó đang hoạt động khá tốt cho đến nay
Felipe Sabino

4

Cách tốt nhất để kiểm tra

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

2

Nếu bạn không cần phân biệt giữa chế độ xem toàn màn hình theo phương thức và chế độ xem không theo phương thức, đó là trường hợp trong dự án của tôi (tôi đang giải quyết vấn đề chỉ xảy ra với biểu mẫu và trang tính), bạn có thể sử dụng modalPresentationStyle thuộc tính của 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

Trong 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
}

Có một vấn đề với trường hợp sử dụng này. Nếu tôi đang ở trong bộ điều khiển chế độ xem gốc của UINavigationController, nó vẫn trả về true mà không có bất kỳ bản trình bày phương thức nào.
mariusLAN

1
Câu lệnh if đầu tiên bao hàm mọi thứ trong câu lệnh if thứ hai, làm cho câu lệnh thứ hai trở nên thừa. Tôi không chắc ý định ở đây là gì.
isoiphone

1

Trong dự án của tôi, tôi có một bộ điều khiển chế độ xem (Chi tiết) có thể được trình bày theo phương thức (khi thêm một mục mới) hoặc đẩy (khi chỉnh sửa một cái hiện có) bằng bộ điều khiển chế độ xem Chính. Khi người dùng chạm vào [Xong], bộ điều khiển chế độ xem Chi tiết gọi phương thức của bộ điều khiển chế độ xem Chính để thông báo rằng nó đã sẵn sàng để đóng. Master phải xác định cách trình bày Chi tiết để biết cách đóng nó. Đây là cách tôi làm điều này:

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

0

Một bản hack như thế này có thể hoạt động.

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
}

Tuy nhiên, tôi nghĩ câu trả lời trước đây của tôi là một giải pháp sạch hơn.


0

Những gì làm việc cho tôi là sau:

// 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);

Theo như tôi đã thử nghiệm, điều này hoạt động cho iOS7 và iOS8. Tuy nhiên, đã không thử trên iOS6.


0

Tôi đã xem xét một chút để tìm câu trả lời phù hợp cho câu hỏi này và tôi không thể tìm thấy câu trả lời nào bao gồm tất cả các trường hợp có thể xảy ra. Tôi đã viết vài dòng mã này dường như thực hiện công việc. Bạn có thể tìm thấy một vài nhận xét nội dòng để tìm ra những gì đã được kiểm tra.

- (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;
}

Hy vọng điều này giúp đỡ.


0

Đây là phiên bản đã sửa đổi của tôi về @ GabrielePetronella's isModal, phiên bản này hoạt động với các bộ điều khiển chế độ xem được chứa trong đó nó đi lên hệ thống phân cấp parentViewController trước tiên. Cũng kéo mã ra thành nhiều dòng để rõ ràng nó đang làm gì.

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
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.