Swift - 如何关闭所有视图控制器以返回到根

时间:2017-11-16 05:37:43

标签: ios swift uiviewcontroller navigation

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

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

我尝试了各种方法,但我当然没有解雇所有的视图控制器。 有一个简单的方法吗?

15 个答案:

答案 0 :(得分:41)

试试这个:

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

它将解除所有viewControllers,直到它有一个presentationController。

修改:如果您想解雇/弹出推送的ViewControllers,您可以使用

self.navigationController?.popToRootViewController(animated: true)

希望它有所帮助。

答案 1 :(得分:18)

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

导航

self.navigationController?.popToRootViewController(animated: true)

用于呈现模态

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

答案 2 :(得分:12)

如果出现,只需要求{ "took": 29, "timed_out": false, "_shards": { "total": 2, "successful": 2, "failed": 0 }, "hits": { "total": 572, "max_score": 1, "hits": [ { "_index": "ref", "_type": "dic", "_id": "12345", "_score": 1, "_source": { "name": "Test name" } }, ... ] } 解雇任何rootViewController

ViewController

答案 3 :(得分:8)

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

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

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

如果你有启动画面,然后登录屏幕,你想进入登录界面,你只需在上面的代码中附加 presentsviewcontroller 即可。

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

答案 4 :(得分:2)

 func  dismiss_all(view: UIView){
   view.window!.rootViewController?.dismiss(animated: true, completion: nil)

 }

答案 5 :(得分:1)

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

func popToRootViewController(animated: Bool)

但是如果你想去特定的控制器只需使用以下功能。

func popToViewController(UIViewController, animated: Bool)

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

答案 6 :(得分:1)

使用此代码可关闭显示的视图控制器并弹出导航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)
    }
}

答案 7 :(得分:1)

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

  

放开序列可以让您关闭已经   提出了。您可以通过链接以下内容在Interface Builder中创建展开序列   按钮或其他适合当前视图的“退出”对象的对象   控制器。当用户点击按钮或与   合适的对象,UIKit在视图控制器层次结构中搜索   能够处理放宽序列的对象。然后解雇   当前视图控制器和任何中间视图控制器   揭示放松目标的目标。

创建放松的场景

  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展开序列的有效目标。

答案 8 :(得分:1)

在Swift 5.3中:

self.navigationController?.popToRootViewController(animated: true)

答案 9 :(得分:0)

要实现您的目标,请修改导航堆栈,然后执行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 :(得分:0)

也许您正在寻找的是轻松的搜索。

  

解开序列可以让您“解开”导航堆栈   通过推送,模式,弹出窗口和其他类型的segue。你用   展开搜索以“返回”导航中的一个或多个步骤   层次结构。

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

答案 11 :(得分:0)

执行此操作的最佳方法是创建一个放松的序列。只需遵循本文档https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/UsingSegues.html。可以用代码或通过界面生成器完成。

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

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

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

场景一

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

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

场景 2

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

这个场景可以通过上面的答案解决 self?.view.window?.rootViewController.dismiss(animated: true) 并将带您回到视图控制器 A

场景 3

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

现在想象你需要从视图控制器 E 一路回到 A

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

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

我相信您可以做些什么来解决此类情况

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

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

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

现在从视图控制器 E,如果你添加这个:

let rootViewController = self?.view.window?.rootViewController as? UINavigationController

rootViewController?.setViewControllers([rootViewController!.viewControllers.first!], 
animated: false)

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

您将被一路传送回视图控制器 A,没有任何警告

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

答案 14 :(得分:-4)

您可以使用此代码段将viewcontrolller设置为rootViewController。

let destination = HomeVC()
let appDelegate:UIApplicationDelegate = UIApplication.shared.delegate!
let initialViewController = destination
let navigationController = UINavigationController(rootViewController: initialViewController)
appDelegate.window??.rootViewController = navigationController
appDelegate.window??.makeKeyAndVisible()