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

Posted

技术标签:

【中文标题】如何从导航控制器一次弹出两个视图?【英文标题】:How do I pop two views at once from a navigation controller? 【发布时间】:2012-01-04 10:26:42 【问题描述】:

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

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

[self.navigationController popViewControllerAnimated:YES];

但是我如何同时做两个呢?

【问题讨论】:

元评论:@lubilis 一直回答是最好的。评分最高的答案在当时还不错,但不再相关。 【参考方案1】:

使用简单的 UINavigationController 扩展

extension UINavigationController 
    func popViewControllers(_ count: Int) 
        guard viewControllers.count > count else  return 
        popToViewController(viewControllers[viewControllers.count - count - 1], animated: true)
    

【讨论】:

【参考方案2】:

斯威夫特 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)

【讨论】:

好一个,我在找什么。谢谢你。【参考方案3】:

这里有两个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)

【讨论】:

对于 Swift(选项 1),您可以将两个 removeLast 替换为 removeLast(2) 调用控制器生命周期的方法呢? DidAppear 等 (Swift 4) 您在这一行中缺少括号 let vc = viewControllers[viewControllers.count - viewsToPop + 1],为了正常工作,您需要将其替换为:let vc = viewControllers[viewControllers.count - (viewsToPop + 1)]let vc = viewControllers[viewControllers.count - viewsToPop - 1] @MMiroslav 你是对的。我已经更新了我的答案。谢谢/Hvala ;) 我在下面发布我的答案后,此答案已更新。基本上是我的代码的副本^_^【参考方案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 是目标控制器。希望能帮助到你。

【讨论】:

【参考方案5】:

您可以使用 UIViewControllers 的堆栈。 1. 获取栈中所有视图控制器的数组。 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)
            
        

【讨论】:

【参考方案6】:

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")
        
    

【讨论】:

这需要更多的支持......我正要写那个扩展。我会用你的谢谢;) @n13 这怎么比budidino的回答好? 使用扩展可以使代码更简洁。您可以采用 budidino 的答案并对其进行扩展,但这可以节省您的精力。此答案还检查错误情况,并优雅地处理错误(例如,尝试弹出比您拥有的更多) 我喜欢这个答案。让我重新思考并更新我发布的答案。我让我的代码弹出到 viewControllers 数组中搜索到的类的最后一个实例,因为这可能是所需的行为。【参考方案7】:
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];   

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

【讨论】:

谢谢你的诡计,我正要以错误的方式做。【参考方案8】:

我在这里没有看到这个答案。如果您只想弹出一些(不是一直到根目录),您可以遍历 self.navigationController.viewControllers 检查类类型,或者如果您有参考使用:

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

【讨论】:

【参考方案9】:

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)

【讨论】:

【参考方案10】:
//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];

【讨论】:

【参考方案11】:

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

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

【讨论】:

imo 这是迄今为止最好的方法,但您应该使用 self.navigationcontroller 引用您的 uinavigation 控制器 我同意,如果用户想将堆栈弹出回某个视图控制器,这是最好的解决方案。假设您不知道哪个视图控制器,您仍然可以实现一个系统,您可以在其中指定要从堆栈中弹出多少视图控制器并使用 objectAtIndex:(allViewControllers.count - 从 allViewControllers 数组中获取目标视图控制器1 - 数量)。 -1 因为数组当然是从零开始的。 在遍历原始 navigator->viewControllers 数组时也有效(无需将其转换为可变数组) 注意!这将从开始-> 到结束迭代堆栈,要完全正确,您应该反转堆栈。因为如果你有几个相同类型的 VC,你会在堆栈中以错误的顺序移除错误的 VC。【参考方案12】:

您可以使用popToRootViewControllerAnimated 弹出到“根”(第一个)视图控制器:

[self.navigationController popToRootViewControllerAnimated:YES];

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

UINavigationController Reference:

弹出堆栈上除根视图控制器之外的所有视图控制器并更新显示。

返回值 从堆栈中弹出的视图控制器数组。

【讨论】:

哈,不敢相信我花了这么长时间才找到这么简单的答案,谢谢! Swift 3: self.navigationController?.popToRootViewController(animated:true); 正是我想要的!【参考方案13】:
    NSMutableArray *newStack = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
    [newStack removeLastObject];
    [newStack removeLastObject];
    [self.navigationController setViewControllers:newStack animated:YES];

【讨论】:

【参考方案14】:

这是我用来返回 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];
    

【讨论】:

【参考方案15】:

你也可以试试这个:-

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

【讨论】:

【参考方案16】:

您可以传递初始视图控制器(您想要返回的那个),然后在最后一个视图中调用此行:

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

L.

【讨论】:

【参考方案17】:

如果您只想一次弹出 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];

不是很好吗? :)

【讨论】:

如果需要弹出三个视图,你会写“UINavigationController+popThrice.m”?????? 你可以传入一个参数来表示要弹出的视图控制器的数量,然后包装 [self popViewControllerAnimated:NO];在一个 for 循环中,count-1。 这不是正确的方法,如果你想把 2,3,... 任何控制器循环识别它然后使用 [self.navigationController popToViewControllerAnimated:YES];。上面提到的这个是非常糟糕的编码,可能会显示闪烁的 UI 和糟糕的用户体验。【参考方案18】:

你可以弹回根视图控制器

[self.navigationController popToRootViewControllerAnimated:YES];

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

【讨论】:

以上是关于如何从导航控制器一次弹出两个视图?的主要内容,如果未能解决你的问题,请参考以下文章

iPhone - 一次弹出多个表单

如何从导航堆栈中的任何位置弹出到任意视图控制器

如何将参数传递给导航控制器内的弹出视图控制器

从弹出控制器推送视图控制器

从导航控制器弹出时如何保持在同一个选项卡中

如何从导航堆栈中推送/弹出uiviewcontroller时收到警报