Проверьте, представлен ли контроллер вида модально или помещен в стек навигации


как я могу, в моем коде контроллера зрения, различать:

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

и presentingViewController и isMovingToParentViewController are 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];

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

14 84

14 ответов:

возьмите с крупинкой соли, не тестировали.

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

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

In Свифт:

func isModal() -> Bool {
    if self.presentingViewController != nil {
        return true
    } else if self.navigationController?.presentingViewController?.presentedViewController == self.navigationController  {
        return true
    } else if self.tabBarController?.presentingViewController is UITabBarController {
        return true
    }

    return false
}

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

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

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

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

extension UIViewController {
    var isModal: Bool {
        if let index = navigationController?.viewControllers.index(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
        }
    }
}

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

Swift 4

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

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

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

DEViewController.h file:

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

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

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

    return false
}

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

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

    // Not pushed
}
else {

    // Pushed
}

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

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

}

if let navigationController = self.navigationController, navigationController.isBeingPresented {
    // being presented
}else{
    // being pushed
}
id presentedController = self.navigationController.modalViewController;
if (presentedController) {
     // Some view is Presented
} else {
     // Some view is Pushed
}

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

для тех, кто задается вопросом, Как сказать ViewController, что он представлен

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

  1. определение enum и property на 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. использование B посмотреть Контроллер

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