Проверьте, представлен ли диспетчер представлений модельным способом или нажат на стек навигации

Как я могу, по моему мнению, определить код контроллера:

  • представлен модально
  • нажата на стек навигации

Оба presentingViewController и isMovingToParentViewController в обоих случаях 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];

Думаю, мне лучше сказать, что мой контроллер просмотра, когда он модальный, вместо того, чтобы пытаться определить.

Ответ 1

Возьмите с солью, не испытайте.

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

Ответ 2

В Swift:

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

Ответ 3

Вы упускаете из виду один метод: 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
    }
}

Ответ 4

self.navigationController!= nil будет означать его в навигации стек.

Чтобы обработать случай, когда текущий контроллер представления нажат во время навигации навигационного контроллера, я добавил несколько строк кода, чтобы проверить, является ли текущий контроллер представления корневым контроллером в стеке навигации.

extension UIViewController{
func isModal() -> Bool {

    if let navigationController = self.navigationController{
        if navigationController.viewControllers.first != self{
            return false
        }
    }

    if self.presentingViewController != nil {
        return true
    }

    if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController  {
        return true
    }

    if self.tabBarController?.presentingViewController is UITabBarController {
        return true
    }

    return false
   }
}

Ответ 5

Swift 5
Вот решение, которое решает проблему, упомянутую в предыдущих ответах, когда isModal() возвращает true, если нажатый UIViewController находится в представленном стеке UINavigationController.

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

До сих пор это работает для меня. Если какие-то оптимизации, пожалуйста, поделитесь.

Ответ 6

Swift 4

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

Ответ 7

Как многие люди здесь предлагают, что методы "проверки" не работают хорошо для всех случаев, в моем проекте я придумал решение для управления этим вручную. Дело в том, что мы обычно управляем презентацией самостоятельно - это не то, что происходит за сценой, и мы должны задуматься.

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

Ответ 8

Предполагая, что все viewControllers, которые вы представляете модально, обернуты внутри нового navigationController (который вы всегда должны делать в любом случае), вы можете добавить это свойство в свой VC.

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

    return false
}

Ответ 9

self.navigationController != nil будет означать его в стеке навигации.

Ответ 10

Чтобы обнаружить, что ваш контроллер выдвинут или нет, просто используйте приведенный ниже код в любом месте:

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

    // Not pushed
}
else {

    // Pushed
}

Я надеюсь, что этот код может помочь любому...

Ответ 11

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

Ответ 12

Если вы используете 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;
}

}

Ответ 13

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

Ответ 14

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

Это даст вам знать, представлен ли viewController или нажат

Ответ 15

Для кого-то, кто задается вопросом, Как сообщить ViewController, что он представлен

если A представляет/толкает B

  • Определите enum и property в B

    enum ViewPresentationStyle {
        case Push
        case Present
    }
    
    //and write property 
    
    var vcPresentationStyle : ViewPresentationStyle = .Push //default value, considering that B is pushed 
    
  • Теперь в диспетчере просмотра 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)
    }
    
  • Использование в B View Controller

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