Як перевірити, чи контролер подання представлений модально або натиснуто на навігаційний стек?


126

Як я можу, на мій погляд контролера, розрізняти:

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

І те, 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];

Я думаю, я краще скажу своєму контролеру перегляду, коли він модальний, а не намагатися визначити.

Відповіді:


125

Взяти з зерном солі, не тестували.

- (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
Я знайшов це в іншій посаді SO. Але, не працює, якщо батьківський контролер висунутого перегляду є модальним; яка ситуація у мене є.
значення-справи

2
Як я писав, presentingViewControllerзавжди є YESв моєму випадку; не допомагає.
сенс-питання

3
presentingViewControllerповертає YESдля висунутого VC, коли є UITabBarControllerістота, встановлена ​​як корінь. Отже, не підходить у моєму випадку.
Євген Дубінін

5
Це не працює, якщо ви представите контролер перегляду, то він натискає інший.
Лі

3
"Це не працює, якщо ви подаєте контролер перегляду, тоді він натискає на інший" Це не є наміром цього, натиснутий контролер подання не представлений.
Colin Swelin

87

У Свіфті :

Додайте прапор для перевірки, чи це модальний тип типу:

// 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
Повинен бути кращим у варі, якvar isModal: Bool {}
malinois

1
@malinois змінено
YannSteph

Що робить останній falseпараметр у returnвиписці?
damjandd

вам потрібні зміни, щоб дозволити presentingIsNavigation = navigationController? .presentingViewController? .presentedViewController == navigationController && navigationController! = nil
famfamfam

78

Ви упускати з виду один метод: isBeingPresented.

isBeingPresented вірно, коли подається контролер перегляду, і хибне при натисканні.

- (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
Я також спробував це перед публікацією, і це не працює, isBeingPresentedє NO. Але я бачу причину зараз, я вставляю свій представлений контролер перегляду в a UINavigationController, і це той, на який я натискаю.
значення-питання

1
Ви не можете натиснути на навігаційний контролер. Можливо, ви мали на увазі, що представляєте контролер навігації.
rmaddy

3
@jowie Використовуйте p, не poдрукуючи примітивне значення. poпризначений для друку об'єктів.
rmaddy

37
Документація для isBeingPresented- Цей метод повертає ТАК лише тоді, коли викликається зсередини viewWillAppear: та viewDidAppear: методів.
funct7

4
@Terrence Мабуть, остання документація не показує цієї інформації, але вона там була раніше. isBeingPresented, isBeingDismissed, isMovingFromParentViewControllerІ isMovingToParentViewControllerдіють тільки в межах 4 -х view[Will|Did][Disa|A]ppearметодів.
rmaddy

29

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

Це для мене працює поки що. Якщо деякі оптимізації, будь ласка, поділіться.


Навіщо потрібно перевіряти tabBarController?.presentingViewController is UITabBarController ? Чи має значення, якщо presentingViewControllerце також UITabBarController?
Hlung

А якщо Навігація Контролера isModalбуде нульовою, повернеться true. Це призначено?
Hlung

28

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

Щоб вирішити випадок, коли поточний контролер перегляду натискається, коли контролер навігації представлений модально, я додав рядки коду, щоб перевірити, чи поточний контролер подання є кореневим контролером у навігаційному стеку.

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

Ну загалом, коли ви представляєте модально, ви ставите viewController на navigationController і представляєте його. Якщо це так, ваше твердження було б неправильним, проте в коді цей випадок обробляється. Удосконаліть свою відповідь :)
E-Riddie

хороша робота, яка стосується всіх випадків використання. кімната для трохи рефакторингу, ймовірно, але все ще upvote !!
Жан Реймонд Дахер

12

Швидкий 4

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

Swift 4.2 / iOS 12. Все ще працює добре, але майте на увазі, що навігаціяController? представлено).
Елі Берк


3

Як багато хто з нас припускає, що методи "перевірки" не спрацьовують у всіх випадках, в моєму проекті я придумав рішення для управління цим вручну. Справа в тому, що ми зазвичай керуємо презентацією самостійно - це не те, що відбувається за сценою, і ми мусимо самоаналізуватись.

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

3

Якщо припустити, що всі viewControllers, які ви представляєте модально, укладені всередині нового NaviController (що завжди потрібно робити), ви можете додати цю властивість до свого ВК.

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

    return false
}

1
що завжди слід робити - будь ласка, поясніть, чому?
Олександр Абакумов

Олександре, ти не повинен.
nickdnk

2

Щоб виявити ваш контролер, натискаєте або не просто використовуйте код нижче в будь-якому місці:

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

    // Not pushed
}
else {

    // Pushed
}

Я сподіваюся, що цей код може допомогти будь-кому ...


1
Цей метод не працює, коли ви використовуєте один і той же клас контролера перегляду в декількох місцях, оскільки він перевіряє тільки його клас. Ви можете замість цього явно перевірити рівність.
гклка

1

self.navigationController != nil означало б, що це в навігаційному стеку.


25
Ще може бути в модальному контролері навігації
ColdLogic

Тож "модальні" та "натиснуті на стек навігації" не є взаємовиключними. Думаючи, що це залежить від контексту, але перевірка того, що self.navigationController не є нульовим, відповідає, чи це контролер перегляду навігаційного контролера.
Даніель

@Daniel Різниця між "підштовхнутим" та "подарованим". "Модальний" не має нічого спільного з цим. Я вважаю, що "ColdLogic" означав "представлений", коли вони сказали "модальний".
rmaddy

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

0

Якщо ви використовуєте 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;
    }
}

0

Swift 5
Це зручне розширення розглядає кілька випадків, ніж попередні відповіді. Це випадки, коли VC (контролер перегляду) є кореневим VC вікна програми, VC додається як дочірнє до батьківського VC. Він намагається повернути істину лише в тому випадку, якщо контролер перегляду представлений на сучасному рівні.

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

Завдяки відповіді Йонауза . Знову з’являється простір для більшої оптимізації. Будь ласка, обговоріть про випадок, який потрібно розглядати у розділі коментарів.


-1

Для когось, хто цікавиться, як сказати 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
        }
    
    }

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

Це дозволить вам дізнатися, чи представлено viewController або натиснуто на нього


4
Ця властивість застаріла.
Моркром
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.