Làm thế nào để kiểm tra xem bộ điều khiển chế độ xem được trình bày theo phương thức hoặc được đẩy trên ngăn xếp điều hướng?


126

Trong mã bộ điều khiển chế độ xem của tôi, làm cách nào để phân biệt giữa:

  • trình bày theo cách thức
  • đẩy trên ngăn xếp điều hướng

Cả hai presentingViewControllerisMovingToParentViewControllerđều nằm YEStrong cả hai trường hợp, do đó không hữu ích lắm.

Điều làm phức tạp mọi thứ là bộ điều khiển chế độ xem cha mẹ của tôi đôi khi là phương thức, trên đó bộ điều khiển chế độ xem được kiểm tra được đẩy.

Hóa ra vấn đề của tôi là tôi đã nhúng HtmlViewControllervào một UINavigationControllercái mà sau đó được trình bày. Đó là lý do tại sao những nỗ lực của riêng tôi và những câu trả lời hay dưới đây không hoạt động.

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

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

Tôi đoán tốt hơn là tôi nên nói với bộ điều khiển chế độ xem của mình khi nó là phương thức, thay vì cố gắng xác định.

Câu trả lời:


125

Hãy với một hạt muối, không thử nghiệm.

- (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
Tôi tìm thấy điều này trong một bài đăng SO khác. Nhưng, không hoạt động nếu cha của bộ điều khiển chế độ xem được đẩy là một phương thức; đó là tình huống tôi đang gặp phải.
ý nghĩa-vấn đề

2
Như tôi đã viết, presentingViewControllerluôn luôn YESở trong trường hợp của tôi; không giúp ích gì.
ý nghĩa-vấn đề

3
presentingViewControllertrả về YEScho VC được đẩy, khi có một mã UITabBarControllerđược đặt làm gốc. Vì vậy, không phù hợp trong trường hợp của tôi.
Yevhen Dubinin

5
Điều này không hoạt động nếu bạn đưa ra một bộ điều khiển chế độ xem sau đó nó đẩy một bộ điều khiển khác.
Lee

3
"Điều này không hoạt động nếu bạn trình bày một bộ điều khiển chế độ xem sau đó nó đẩy một bộ điều khiển khác" Đó không phải là mục đích của điều này, bộ điều khiển chế độ xem được đẩy không được trình bày.
Colin Swelin vào

87

Trong Swift :

Thêm một cờ để kiểm tra xem đó có phải là một phương thức theo loại lớp:

// 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
Nên tốt hơn trong một var, giống nhưvar isModal: Bool {}
Malinois

1
@malinois đã được thay đổi
YannSteph

falseTham số cuối cùng trong returncâu lệnh làm gì?
damjandd

bạn cần thay đổi để cho phép PresentationIsNavigation = navigationController? .presentingViewController? .presentedViewController == navigationController && navigationController! = nil
famfamfam

78

Bạn bỏ qua một phương pháp: isBeingPresented.

isBeingPresented là đúng khi trình điều khiển chế độ xem đang được hiển thị và sai khi được đẩy.

- (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
Tôi cố gắng này quá trước khi gửi bài, và nó không làm việc, isBeingPresentedNO. Nhưng tôi đã hiểu lý do ngay bây giờ, tôi đang nhúng bộ điều khiển chế độ xem đã trình bày của mình vào một UINavigationController, và đó là cái tôi đang đẩy.
ý nghĩa-vấn đề

1
Bạn không thể đẩy bộ điều khiển điều hướng. Có lẽ ý bạn là bạn đang trình bày bộ điều khiển điều hướng.
rmaddy

3
@jowie Sử dụng p, không phải pokhi in giá trị nguyên thủy. polà để in các đối tượng.
rmaddy

37
Documentation for isBeingPresented- Phương thức này chỉ trả về CÓ khi được gọi từ bên trong các phương thức viewWillAppear: và viewDidAppear:.
funct

4
@Terrence Có vẻ như tài liệu mới nhất không hiển thị thông tin đó nhưng nó đã từng ở đó. Các isBeingPresented, isBeingDismissed, isMovingFromParentViewControllerisMovingToParentViewControllerchỉ có giá trị trong 4 view[Will|Did][Disa|A]ppearphương pháp.
rmaddy

29

Swift 5
Đây là giải pháp giải quyết vấn đề được đề cập với các câu trả lời trước đó, khi isModal()trả về truenếu được đẩy UIViewControllernằm trong một UINavigationControllerngăn xếp được trình bày .

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

Nó làm việc cho tôi cho đến nay. Nếu một số tối ưu hóa, xin vui lòng chia sẻ.


Tại sao bạn cần phải kiểm tra tabBarController?.presentingViewController is UITabBarController ? Có vấn đề gì không nếu đó presentingViewControllercũng là một UITabBarController?
Hlung

Và nếu điều hướngController là nil, isModalsẽ trả về true. Đây có phải là dự định?
Hlung

28

self.navigationController! = nil có nghĩa là nó nằm trong ngăn xếp điều hướng.

Để xử lý trường hợp bộ điều khiển chế độ xem hiện tại được đẩy trong khi bộ điều khiển điều hướng được trình bày theo phương thức, tôi đã thêm một số dòng mã để kiểm tra xem bộ điều khiển chế độ xem hiện tại có phải là bộ điều khiển gốc trong ngăn xếp điều hướng hay không.

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

Nói chung, khi bạn trình bày theo phương thức, bạn đặt viewController trên một điều hướngController và bạn trình bày nó. Nếu đó là trường hợp, tuyên bố của bạn sẽ sai, tuy nhiên trên mã, trường hợp này được xử lý. Hãy cải thiện câu trả lời của bạn :)
E-Riddie

công việc tốt giải quyết tất cả các trường hợp sử dụng. Có thể là chỗ cho một chút tái cấu trúc nhưng vẫn ủng hộ !!
Jean Raymond Daher

12

Swift 4

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

Swift 4.2 / iOS 12. Vẫn hoạt động tốt, nhưng hãy lưu ý rằng navigationController? .PresentingViewController? .PresentedViewController === navigationController sẽ đánh giá thành true nếu cả hai đều là nil (ví dụ: nếu bạn gọi nó trên bộ điều khiển chế độ xem chưa được trình bày).
Eli Burke

7

Swift 5. Sạch sẽ và đơn giản.

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

1
điều này đã thực hiện thủ thuật cho tôi
Radu Ursache

3

Như nhiều người ở đây đề xuất, rằng các phương pháp "kiểm tra" không hoạt động tốt cho mọi trường hợp, trong dự án của tôi, tôi đã đưa ra giải pháp để quản lý điều đó theo cách thủ công. Vấn đề là, chúng ta thường tự mình quản lý bài thuyết trình - đây không phải là những gì diễn ra phía sau hậu trường và chúng ta phải xem xét nội tâm.

DEViewController.h tập tin:

#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

Các bản trình bày bây giờ có thể được quản lý theo cách này:

đẩy trên ngăn xếp điều hướng:

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

được trình bày theo phương thức với điều hướng:

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

được trình bày theo phương thức:

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

Ngoài ra, trong DEViewControllerchúng tôi có thể thêm một dự phòng để "kiểm tra" nếu thuộc tính nói trên bằng 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

Giả sử rằng tất cả các viewController mà bạn trình bày theo phương thức được bao bọc bên trong một navigationController mới (điều mà bạn nên làm luôn), bạn có thể thêm thuộc tính này vào VC của mình.

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

    return false
}

1
mà bạn luôn luôn nên làm - vui lòng giải thích tại sao?
Alexander Abakumov

Alexander, bạn không nên, thực sự.
nickdnk

2

Để phát hiện bộ điều khiển của bạn có được đẩy hay không, chỉ cần sử dụng mã bên dưới ở bất kỳ đâu bạn muốn:

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

    // Not pushed
}
else {

    // Pushed
}

Tôi hy vọng mã này có thể giúp bất cứ ai ...


1
Phương thức này không hoạt động khi bạn sử dụng cùng một lớp bộ điều khiển chế độ xem ở nhiều nơi, vì nó chỉ kiểm tra lớp của nó. Thay vào đó, bạn có thể kiểm tra sự bình đẳng một cách rõ ràng.
gklka

1

self.navigationController != nil có nghĩa là nó nằm trong ngăn xếp điều hướng.


25
Vẫn có thể ở trong bộ điều khiển điều hướng phương thức
ColdLogic

Vì vậy, 'modal' và 'push on navigation stack' không loại trừ lẫn nhau. Suy nghĩ điều này phụ thuộc vào ngữ cảnh, nhưng việc kiểm tra xem self.navigationController có phải là nil không sẽ trả lời liệu đó có phải là bộ điều khiển chế độ xem của bộ điều khiển điều hướng hay không.
Daniel

@Daniel Sự khác biệt giữa "được đẩy" và "được trình bày". "Phương thức" không liên quan gì đến nó. Tôi tin rằng "ColdLogic" có nghĩa là "được trình bày" khi họ nói "phương thức".
rmaddy

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

0

Nếu bạn đang sử dụng ios 5.0 trở lên, vui lòng sử dụng mã này

-(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
Tiện ích mở rộng tiện dụng này xử lý nhiều trường hợp hơn các câu trả lời trước. Các trường hợp này VC (view controller) là VC gốc của cửa sổ ứng dụng, VC được thêm vào dưới dạng VC con vào VC mẹ. Nó cố gắng trả về true chỉ khi bộ điều khiển chế độ xem được trình bày theo phương thức.

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

Cảm ơn câu trả lời của Jonauz . Một lần nữa có không gian để tối ưu hóa hơn. Vui lòng thảo luận về trường hợp cần được xử lý trong phần bình luận.


-1

Đối với một số người đang thắc mắc, Làm thế nào để nói với ViewController rằng nó đang được trình bày

nếu Ađang trình bày / thúc đẩyB

  1. Xác định một enumpropertytrongB

    enum ViewPresentationStyle {
        case Push
        case Present
    }
    
    //and write property 
    
    var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
  2. Bây giờ trong Abộ điều khiển chế độ xem, hãy cho biết Bnếu nó đang được trình bày / đẩy bằng cách gánpresentationStyle

    func presentBViewController() {
        let bViewController = B()
        bViewController.vcPresentationStyle = .Present //telling B that it is being presented
        self.presentViewController(bViewController, animated: true, completion: nil)
    }
  3. Sử dụng trong 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
}

Điều này sẽ cho bạn biết nếu viewController được trình bày hoặc đẩy


4
Thuộc tính này không được dùng nữa.
Morkrom
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.