【问题标题】:Swift - How to dismiss all of view controllers to go back to rootSwift - 如何关闭所有视图控制器以返回根目录
【发布时间】:2018-04-29 13:29:01
【问题描述】:

我希望我的应用可以在每次用户需要时转到第一个视图控制器。

所以我想创建一个函数来关闭所有视图控制器,无论它是在导航控制器中推送还是以模态方式呈现或打开任何方法。

我尝试了各种方法,但我确实没有关闭所有视图控制器。 有什么简单的方法吗?

【问题讨论】:

  • 你可以使用navigationcontroler.poptorootcontroller
  • 您可以更改根视图控制器。
  • 重置应用程序窗口的rootviewcontroller将解决问题。
  • 你在使用 segues 吗?如果是这样,展开 segue 是最简单的方法
  • 谢谢大家。我把你的意见放在一起解决了。

标签: ios swift uiviewcontroller navigation


【解决方案1】:

试试这个:

self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)

它应该关闭根视图控制器上方的所有视图控制器。

如果这不起作用,您可以通过运行这样的 while 循环手动执行此操作。

func dismissViewControllers() {

    guard let vc = self.presentingViewController else { return }

    while (vc.presentingViewController != nil) {
        vc.dismiss(animated: true, completion: nil)
    }
}

它会关闭所有 viewController,直到它有一个 presentingController。

编辑:如果你想关闭/弹出推送的 ViewController,你可以使用

self.navigationController?.popToRootViewController(animated: true)

希望对你有帮助。

【讨论】:

  • 谢谢。它完全适用于所有呈现的视图控制器,但不适用于推送的视图控制器(如果根视图控制器是导航控制器)。所以我也一起反映了使用popToRootViewController的其他意见,我解决了它:)
  • @Byoth 编辑了答案。
  • 如果我想呈现视图控制器怎么办..直到一个特定的计数..从一个 for 循环..说如果计数是 5..那么应该呈现 5 次相同的视图控制器..是有可能吗?
  • @ZahurafzalMirza 你想在弹出 5 次后展示一个 viewController 还是你想展示一个单一的视图控制器 5 次?
  • 不,我想展示一个单一的视图控制器 5 次。我已经完成了编码,但只展示了最后一个。你能给我提供一个如何做的概述吗?跨度>
【解决方案2】:

如果您使用的是导航,则可以使用第一个 或者,如果您以模态方式呈现,则可以第二个:

用于导航

self.navigationController?.popToRootViewController(animated: true)

用于模态展示

self.view.window!.rootViewController?.dismissViewControllerAnimated(false, completion: nil)

【讨论】:

  • Erhan Demirci 我的亲爱的
  • Swift 3.0 以模态方式呈现 self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
  • “For Presenting Modally”窗口后的感叹号让我的应用程序崩溃。所以我做了 self.view.window?.rootViewController?.dismissViewControllerAnimated(false, completion: nil)
  • @Markinson 是的'!'和 '?'两者都用于定义变量可以为 nil 或不为 nil。如果您将其声明为“!”然后变量不能为nil,如果它为nil,那么它将导致崩溃。 “?”防止应用崩溃。
【解决方案3】:

大家好,这里是Swift-4的答案。

要返回根视图控制器,只需调用一行代码即可完成工作。

 self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)

如果你有启动屏幕,然后是登录屏幕,你想进入登录屏幕,你可以简单地在上面的代码中附加 presentedviewcontroller

self.view.window?.rootViewController?.presentedViewController!.dismiss(animated: true, completion: nil)

【讨论】:

    【解决方案4】:

    只需让您的rootViewController 拒绝任何ViewController(如果正在演示)。

    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
       appDelegate.window?.rootViewController?.dismiss(animated: true, completion: nil)
       (appDelegate.window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: true)
    }
    

    【讨论】:

    • 谢谢。它完全适用于所有呈现的视图控制器,但不适用于推送的视图控制器(如果根视图控制器是导航控制器)。所以我也一起反映了使用popToRootViewController的其他意见,我解决了它:)
    • 为您编辑了答案。如果根是 UINavigationController,它将首先关闭所有 viewController,然后弹出所有 viewController。
    • 当我没有 self 对当前呈现窗口的引用时,这对我有用
    【解决方案5】:

    使用此代码关闭显示的视图控制器并弹出导航 rootviewcontroller swift 4

    // MARK:- Dismiss and Pop ViewControllers
    func dismissPopAllViewViewControllers() {
        if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
            appDelegate.window?.rootViewController?.dismiss(animated: true, completion: nil)
            (appDelegate.window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: true)
        }
    }
    

    【讨论】:

    【解决方案6】:

    斯威夫特 5.4:

    self.navigationController?.popToRootViewController(animated: true)
    

    【讨论】:

      【解决方案7】:

      返回初始视图控制器的策略可能因视图控制器的堆叠而异。

      可能有多种情况,根据您的情况,您可以决定哪种方法最好。

      场景 1

      • 导航控制器设置为根视图控制器
      • 导航控制器将视图控制器 A 设置为根
      • 导航控制器推送视图控制器 B
      • 导航控制器推送视图控制器 C

      这是一个简单的场景,navigationController?.popToRootViewController(animated:true) 将在任何视图控制器中工作并将您返回到视图控制器 A

      场景 2

      • 导航控制器设置为根视图控制器
      • 导航控制器将视图控制器 A 设置为根
      • 视图控制器 A 呈现视图控制器 B
      • 视图控制器 B 呈现视图控制器 C

      这种情况可以通过上面的答案来解决 self?.view.window?.rootViewController.dismiss(animated: true) 会带你回到 View Controller A

      场景 3

      • 导航控制器 1 被设置为根视图控制器
      • 导航控制器 1 将视图控制器 A 设置为根
      • 导航控制器 1 推送视图控制器 B
      • 视图控制器 B 呈现导航控制器 2
      • 导航控制器 2 将视图控制器 D 设置为根
      • 导航控制器 2 推送视图控制器 E

      现在假设您需要从 View Controller E 一直返回到 A

      这次使用上面的 2 个答案将无法解决您的问题,因为如果导航控制器不在屏幕上,则无法弹出到根目录。

      您可能会尝试添加计时器和侦听器以关闭视图控制器,然后弹出哪些可以工作,我认为上面有一个类似这样的答案,带有函数dismissPopAllViewViewControllers - 我注意到这会导致异常行为并带有此警告Unbalanced calls to begin/end appearance transitions for

      我相信你可以做的是解决这种情况

      • 首先从导航控制器本身展示您的模态视图控制器
      • 现在您可以更好地控制自己想做的事情了

      所以我先把上面的改成这个架构:

      • 导航控制器 1 设置为根视图控制器(相同)
      • 导航控制器 1 将视图控制器 A 设置为根(相同)
      • 导航控制器 1 推送视图控制器 B(相同)
      • 导航控制器 1 呈现导航控制器 2(更改)
      • 导航控制器 2 将视图控制器 D 设置为根(相同)
      • 导航控制器 2 推送视图控制器 E(相同)

      现在从 View Controller E 开始,如果你添加这个:

      let rootViewController = self?.view.window?.rootViewController as? UINavigationController
      
      rootViewController?.setViewControllers([rootViewController!.viewControllers.first!], 
      animated: false)
      
      rootViewController?.dismiss(animated: true, completion: nil)
      

      您将在没有任何警告的情况下一路传送回视图控制器 A

      您可以根据自己的要求进行调整,但这是关于如何重置复杂视图控制器层次结构的概念。

      【讨论】:

        【解决方案8】:

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

        func popToRootViewController(animated: Bool)
        

        但是,如果您想转到特定的控制器,只需使用以下功能。

        func popToViewController(UIViewController, animated: Bool)
        

        弹出视图控制器,直到指定的视图控制器位于导航堆栈的顶部。

        【讨论】:

          【解决方案9】:

          要实现你想要的,修改你的导航堆栈,然后做 popViewController。

          let allControllers = NSMutableArray(array: navigationController!.viewControllers)
          let vcCount = allControllers.count
          for _ in 0 ..< vcCount - 2 {
              allControllers.removeObject(at: 1)
          }
          // now, allControllers[0] is root VC, allControllers[1] is presently displayed VC. write back to nav stack
          navigationController!.setViewControllers(allControllers as [AnyObject] as! [UIViewController], animated: false)
          // then pop root VC
          navigationController!.popViewController(animated: true)
          

          有关进一步操作导航堆栈的方法,请参阅this。如果您最顶层的 VC 是模态的,请在上面的代码之前先将其关闭。

          【讨论】:

            【解决方案10】:

            创建一个 Unwind Segue(您可以在https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html Apple Inc. 版权所有)找到它

            Unwind segues 可以让你关闭已经存在的视图控制器 提出了。您可以在 Interface Builder 中通过链接 按钮或其他合适的对象到当前视图的 Exit 对象 控制器。当用户点击按钮或与 合适的对象,UIKit 在视图控制器层次结构中搜索 一个能够处理 unwind segue 的对象。然后它驳回 当前视图控制器和任何中间视图控制器 揭示 unwind segue 的目标。

            创建一个放松的转场

            1. 选择应在展开转场结束时出现在屏幕上的视图控制器。

            2. 在您选择的视图控制器上定义一个展开操作方法。

            该方法的 Swift 语法如下:

            @IBAction func myUnwindAction(unwindSegue: UIStoryboardSegue)
            

            此方法的 Objective-C 语法如下:

            - (IBAction)myUnwindAction:(UIStoryboardSegue*)unwindSegue
            

            3。导航到启动展开操作的视图控制器。

            1. 按住 Control 键单击应该启动展开转场的按钮(或其他对象)。这个元素应该在你想要关闭的视图控制器中。

            2. 拖动到视图控制器场景顶部的 Exit 对象。

            https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/Art/segue_unwind_linking_2x.png

            1. 从关系面板中选择您的放松操作方法。

            在尝试在 Interface Builder 中创建相应的展开转场之前,您必须在其中一个视图控制器中定义展开操作方法。该方法的存在是必需的,它会告诉 Interface Builder 有一个有效的展开 segue 目标。

            【讨论】:

              【解决方案11】:

              如果有人正在寻找问题答案的 Objective-C 实现,

              [self.view.window.rootViewController dismissViewControllerAnimated:true completion:nil];
              

              【讨论】:

                【解决方案12】:
                 func  dismiss_all(view: UIView){
                   view.window!.rootViewController?.dismiss(animated: true, completion: nil)
                
                 }
                

                【讨论】:

                • 你应该小心强制窗口。如果窗口为零,应用程序将崩溃。使其可选将防止它崩溃
                【解决方案13】:

                也许你正在寻找的是放松segue。

                Unwind segues 为您提供了一种“展开”导航堆栈的方式 通过 push、modal、popover 和其他类型的 segue。你用 展开 segues 以“返回”导航中的一个或多个步骤 层次结构。

                文档链接: https://developer.apple.com/library/archive/technotes/tn2298/_index.html

                【讨论】:

                • 嗨,欢迎来到 Stack Overflow!除了摘录和文档链接之外,您能否发布一个创建 segue 的示例?谢谢!
                • 为了易读性,我将添加另一个答案。
                【解决方案14】:

                最好和首选的方法是创建一个 unwind segue。只需遵循此文档https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html。它可以在代码中完成,也可以通过界面生成器完成。

                【讨论】:

                • 点评来源: 嗨,虽然链接是分享知识的好方法,但如果它们将来被破坏,它们将不会真正回答问题。将回答问题的链接的基本内容添加到您的答案中。如果内容太复杂或太大而无法在此处放置,请描述所提出解决方案的总体思路。请记住始终保留对原始解决方案网站的链接引用。见:How do I write a good answer?
                • 问题没有提到使用有自己问题的segues
                猜你喜欢
                • 1970-01-01
                • 2021-06-17
                • 2016-03-23
                • 1970-01-01
                • 2017-11-19
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多