Як вивести одночасно два подання з контролера навігації?


92

Я хочу перейти до третього подання в стеці навігації назад до першого подання.

Я знаю, як одразу подати одне представлення:

[self.navigationController popViewControllerAnimated:YES];

Але як мені зробити дві відразу?


2
Мета-коментар: @lubilis відповідь на весь шлях є найкращим. Відповіді з найвищим рейтингом були хорошими у свій час, але вони вже не актуальні.
n13,

Відповіді:


133

Ви також можете спробувати перейти між стеком навігаційного контролера

NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
    if ([aViewController isKindOfClass:[RequiredViewController class]]) {
        [self.navigationController popToViewController:aViewController animated:NO];
    }
}

6
imo це найкращий метод на сьогоднішній день, але вам слід посилатися на свій контролер навігації за допомогою self.navigationcontroller
henghonglee

2
Я згоден, це найкраще рішення, якщо користувач хотів би повернути стек назад до певного контролера перегляду. Скажімо, ви не знаєте, який саме контролер вигляду, ви все ще можете реалізувати систему, де ви можете вказати, скільки контролерів виглядів ви хочете вискочити з стеку і отримати цільовий контролер вигляду з масиву allViewControllers з objectAtIndex: (allViewControllers.count - 1 - сума). -1, оскільки масиви мають нульовий курс.
Йован

1
Полюбіть це рішення. Саме те, що я шукав
Designer023

3
Працює також при ітерації над початковим масивом навігатора-> viewControllers (не потрібно перетворювати його на змінний масив)
Арік Сегал

ПРИМІТКА! Що це буде повторювати стек з початку -> до кінця, щоб бути точно правильним, слід змінити стек. Тому що якщо у вас є кілька однотипних ВК, ви вилучите неправильний ВК в неправильному порядку в стеку.
StackUnderflow

71

Ось два UINavigationControllerрозширення, які можуть вирішити вашу проблему. Я б порекомендував використовувати перший, який вискакує в UIViewControllera певного класу:

extension UINavigationController {

  func popToViewController(ofClass: AnyClass, animated: Bool = true) {
    if let vc = viewControllers.filter({$0.isKind(of: ofClass)}).last {
      popToViewController(vc, animated: animated)
    }
  }

  func popViewControllers(viewsToPop: Int, animated: Bool = true) {
    if viewControllers.count > viewsToPop {
      let vc = viewControllers[viewControllers.count - viewsToPop - 1]
      popToViewController(vc, animated: animated)
    }
  }

}

і використовувати його так:

// pop to SomeViewController class
navigationController?.popToViewController(ofClass: SomeViewController.self)

// pop 2 view controllers
navigationController?.popViewControllers(viewsToPop: 2)

3
Для Swift (варіант 1) ви можете замінити їх на removeLastпросто removeLast(2).
Домінік К

А як щодо методів виклику життєвого циклу контролерів? DidAppear and ect
Mike

1
(Swift 4) У цьому рядку вам бракує дужок let vc = viewControllers[viewControllers.count - viewsToPop + 1], для коректної роботи вам потрібно замінити його на: let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]абоlet vc = viewControllers[viewControllers.count - viewsToPop - 1]
MMiroslav

@MMiroslav ти маєш рацію. Я оновив свою відповідь. Дякую / Хвала;)
budidino

1
Ця відповідь була оновлена ​​після того, як я розмістив свою відповідь нижче. По суті, копія мого коду ^ _ ^
lubilis

44

Ви можете перейти до "кореневого" (першого) контролера перегляду за допомогою popToRootViewControllerAnimated:

[self.navigationController popToRootViewControllerAnimated:YES];

// If you want to know what view controllers were popd:
// NSArray *popdViewControllers = [self.navigationController popToRootViewControllerAnimated:YES];

UINavigationControllerДовідково :

Вискакує всі контролери подання у стеку, окрім кореневого контролера перегляду, та оновлює дисплей.

Повернене значення
Масив контролерів подання, які вискакують із стеку.


1
ха, не можу повірити, що я так довго шукав таку просту відповідь, дякую!
Адам Уейт

1
Swift 3: self.navigationController? .PopToRootViewController (анімоване: true);
dianakarenms

Саме те, що я шукав!
Canucklesandwich

29
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

objectAtIndex: 1 -> ви можете передати будь-який індекс, до якого ви хочете потрапити


Дякую за фокус, я якраз збирався зробити це неправильно.
Лінус

18

Свіфт 2 - xCode 7.3

Це може бути дуже корисним розширенням pop UIViewControllers:

extension UINavigationController {

    func popToViewControllerOfType(classForCoder: AnyClass) {
        for controller in viewControllers {
            if controller.classForCoder == classForCoder {
                popToViewController(controller, animated: true)
                break
            }
        }
    }

    func popViewControllers(controllersToPop: Int, animated: Bool) {
        if viewControllers.count > controllersToPop {
            popToViewController(viewControllers[viewControllers.count - (controllersToPop + 1)], animated: animated)
        } else {
            print("Trying to pop \(controllersToPop) view controllers but navigation controller contains only \(viewControllers.count) controllers in stack")
        }
    }
}

2
Це потребує більшого голосування ... Я якраз збирався написати це розширення. Я просто використаю ваші подяки;)
n13

1
@ n13 як це краще, ніж відповідь budidino?
Крашалот

1
Використання розширення робить набагато чистіший код. Ви можете взяти відповідь budidino і зробити з неї продовження, але це заощадить ваші зусилля. Також ця відповідь перевіряє випадки помилок і обробляє помилки витончено (наприклад, намагаючись вивести більше, ніж у вас є)
n13

1
Мені подобається така відповідь. Змусив мене переглянути і оновити відповідь, яку я розмістив. Я зробив свій код спливаючим до останнього екземпляра шуканого класу в масиві viewControllers, оскільки це, мабуть, бажана поведінка.
budidino

15

Якщо ви просто хочете вивести 2 відразу, оскільки ваш rootViewController (набагато) „глибший“, тоді 2, ви можете подумати про додавання категорії до UIviewController, наприклад:

UINavigationController + popTwice.h

#import <UIKit/UIKit.h>
@interface UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated;

@end

UINavigationController + popTwice.m

#import "UINavigationController+popTwice.h"

@implementation UINavigationController (popTwice)

- (void) popTwoViewControllersAnimated:(BOOL)animated{
    [self popViewControllerAnimated:NO];
    [self popViewControllerAnimated:animated];
}

@end

Імпортуйте категорію #import "UINavigationController+popTwice.h" десь у вашій реалізації та використовуйте цей рядок коду для виведення 2 контролерів одночасно:

[self.navigationController popTwoViewControllersAnimated:YES];

хіба це не чудово? :)


6
що, якщо вам потрібно вивести три подання, ви напишете "UINavigationController + popThrice.m" ??????
Зустріньтесь

8
ви можете просто передати параметр для кількості viewControllers, щоб вискочити та обернути [self popViewControllerAnimated: NO]; в межах циклу for, count-1.
noRema

Це не вірний спосіб, якщо ви хочете підписати до 2,3, ... будь-який контролер ідентифікує його по циклу, а потім використовує [self.navigationController popToViewControllerAnimated: YES] ;. Це вище згадане дуже погане кодування і може показати мерехтливий інтерфейс та поганий досвід користувача.
Вікі Дас,

10

Свіфт 4:

func popViewControllerss(popViews: Int, animated: Bool = true) {
    if self.navigationController!.viewControllers.count > popViews
    {
        let vc = self.navigationController!.viewControllers[self.navigationController!.viewControllers.count - popViews - 1]
         self.navigationController?.popToViewController(vc, animated: animated)
    }
}

Тоді скористайтеся цим методом

self.popViewControllerss(popViews: 2)

Хороший, те, що я шукав. Дякую тобі.
maddysan

6

Ви також можете спробувати це: -

[self.navigationController popToViewController:yourViewController animated:YES];

6
//viewIndex = 1;
//viewIndex = 2;
//viewIndex = 3;

// **[viewControllers objectAtIndex: *put here your viewindex number*]

NSArray *viewControllers = [self.navigationController viewControllers];
[self.navigationController popToViewController:[viewControllers objectAtIndex:viewIndex] animated:NO];

4
    NSMutableArray *newStack = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
    [newStack removeLastObject];
    [newStack removeLastObject];
    [self.navigationController setViewControllers:newStack animated:YES];

4

У Swift 3 ви можете витягти один, два або більше контролерів огляду з навігаційного контролера так

let viewControllers = self.navigationController!.viewControllers as [UIViewController]
    for aViewController:UIViewController in viewControllers {
        if aViewController.isKind(of: FromWhereYouWantToGoController.self) {
            _ = self.navigationController?.popToViewController(aViewController, animated: true)
        }
    }

Тут FromWhereYouWantToGoController - контролер призначення. Сподіваюся, це допоможе.


3

Ви можете передати початковий контролер перегляду (той, до якого ви хочете повернутися), а потім викликати цей рядок в останньому поданні:

[self.navigationController popToViewController:yourInitialViewController animated:YES];

Л.


3

Я не бачив цієї відповіді тут. Якщо ви хочете вивести лише кілька (не зовсім до кореня), ви можете просто перебирати self.navigationController.viewControllers, перевіряючи типи класів, або якщо у вас є посилання, використовуйте це:

for (UIViewController *aViewController in self.navigationController.viewControllers) {
   if ([aViewController isKindOfClass:[SMThumbnailViewController class]]) {
      [self.navigationController popToViewController:aViewController animated:YES];
   }
}

2

Ви можете повернутися до кореневого контролера подання

[self.navigationController popToRootViewControllerAnimated:YES];

або, якщо подання, до якого ви хочете потрапити, не перше, вам потрібно буде знову з’явитись у поданні вашого попереднього переглядуWillAppear


2

Ось невеличка функція, яку я використовую для повернення X ViewControllers:

-(void)backMultiple:(id)data {
    int back = 2; //Default to go back 2 
    int count = [self.navigationController.viewControllers count];

    if(data[@"count"]) back = [data[@"count"] intValue];

    //If we want to go back more than those that actually exist, just go to the root
    if(back+1 > count) {
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    //Otherwise go back X ViewControllers 
    else {
        [self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:count-(back+1)] animated:YES];
    }
}

2

Версія Swift станом на (Swift 1.2 / Xcode 6.3.1) спливає двічі або більше

 var viewControllers = self.navigationController?.viewControllers
 viewControllers?.removeLast()
 viewControllers?.removeLast()
 self.navigationController?.setViewControllers(viewControllers, animated: true)

або

 var viewControllers = self.navigationController?.viewControllers
 var viewsToPop = 2
 var end = (viewControllers?.count)!
 var start = end - viewsToPop
 viewControllers?.removeRange(Range<Int>(start: start, end: end))
 self.navigationController?.setViewControllers(viewControllers, animated: true)

1

Ви можете використовувати стек UIViewControllers. 1. Виберіть масив усіх viewControllers у стеку. 2. Перегляньте весь масив і знайдіть бажаний viewController
, зіставляючи тип класу. 3. Відкрийте viewController.

func popToSpecificViewC
{
let viewControllers: [UIViewController] = self.navigationController!.viewControllers as [UIViewController];
        for viewController:UIViewController in viewControllers
        {
            if viewController.isKind(of: WelcomeViewC.self)
            {
                _ = self.navigationController?.popToViewController(viewController, animated: true)
            }
        }
}

0

Використання простого розширення UINavigationController :

extension UINavigationController {
    func popViewControllers(_ count: Int) {
        guard viewControllers.count > count else { return }
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.