如何从导航控制器一次弹出两个视图?


90

我想弹出导航堆栈上的第三个视图回到第一个视图。

我知道如何一次弹出一个视图:

[self.navigationController popViewControllerAnimated:YES];

但是我该如何一次做两个?


2
Meta评论:@lubilis一直以来都是最好的答案。评分最高的答案在当时是不错的,但不再相关。
n13

Answers:


132

您也可以尝试在导航控制器堆栈之间跳转

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引用uinavigation控制器
henghonglee 2012年

2
我同意,这是最好的解决方案,如果用户希望将堆栈弹出到某个ViewController。假设您不知道是哪个viewcontroller,您仍然可以实现一个系统,在该系统中,您可以指定要弹出多少个ViewController,并使用objectAtIndex:(allViewControllers.count- 1-金额)。-1是因为数组是基于零的课程。
Jovan 2012年

1
喜欢这个解决方案。正是我想要的东西
Designer023

3
遍历原始navigator-> viewControllers数组时也可以工作(无需将其转换为可变数组)
Arik Segal

注意!这样将使堆栈从开始->到结束进行迭代,要完全正确,您应该反转堆栈。因为如果您有多个相同类型的VC,您将以错误的顺序在堆栈中删除错误的VC。
StackUnderflow

71

这里有两个UINavigationController扩展可以解决您的问题。我建议使用第一个弹出UIViewController特定类别的:

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),您可以将它们替换为removeLastjust removeLast(2)
多米尼克K

调用控制器生命周期的方法呢?DidAppear and ect
Mike Glukhov

1
(快速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 18/09/26

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(animated:true);
dianakarenms

正是我想要的!
Canucklesandwich

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

objectAtIndex:1->您可以传递要弹出的任何索引


感谢您的技巧,我将以错误的方式进行操作。
Linus 2013年

18

Swift 2-xCode 7.3

这对于弹出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的答案更好?
Crashalot

1
使用扩展名可使代码更简洁。您可以采用budidino的答案并对其进行扩展,但这可以节省您的精力。另外,此答案还会检查错误情况,并优雅地处理错误(例如,尝试弹出超出您所能
承受的范围

1
我喜欢这个答案。让我重新考虑并更新了我发布的答案。我将代码弹出到viewControllers数组中搜索到的类的最后一个实例,因为这可能是所需的行为。
budidino '18

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循环中,计数为1。
noRema 2012年

这不是正确的方法,如果您想添加到2,3,...任何控制器通过循环标识它,然后使用[self.navigationController popToViewControllerAnimated:YES];。上面提到的这是非常糟糕的编码,可能显示闪烁的UI和糟糕的用户体验。
维姬·达斯

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

L.


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

或者,如果您要弹出的视图不是第一个,则需要在先前视图的viewWillAppear中再次弹出


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 1.2 / Xcode 6.3.1)开始弹出两次或更多次的Swift版本

 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)
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.