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

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

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

[self.navigationController popViewControllerAnimated:YES];

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

【问题讨论】:

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

标签: ios iphone uinavigationcontroller


【解决方案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 中再次弹出

                      【讨论】:

                        猜你喜欢
                        • 2011-12-27
                        • 1970-01-01
                        • 2012-02-08
                        • 1970-01-01
                        • 2020-10-04
                        • 2014-03-21
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-07-25
                        相关资源
                        最近更新 更多