ios 同时关闭多个视图控制器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30990507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:33:35  来源:igfitidea点击:

Dismiss more than one view controller simultaneously

iosswiftviewcontrollerdismiss

提问by codeinjuice

I'm making a game using SpriteKit. I have 3 viewControllers: selecting level vc, game vc, and win vc. After the game is over, I want to show the win vc, then if I press OK button on the win vc, I want to dismiss the win vc AND the game vc (pop two view controllers out of the stack). But I don't know how to do it because if I call

我正在使用 SpriteKit 制作游戏。我有 3 个 viewController:选择关卡 vc、游戏 vc 和 win vc。游戏结束后,我想显示 win vc,然后如果我按下 win vc 上的 OK 按钮,我想关闭 win vc 和游戏 vc(从堆栈中弹出两个视图控制器)。但我不知道该怎么做 因为如果我打电话

self.dismissViewControllerAnimated(true, completion: {})    

the win vc (top of the stack) is dismissed, so I don't know where to call it again to dismiss the game vc. Is there any way I can fix this without using navigation controller?

win vc(栈顶)被解散,所以我不知道在哪里再次调用它来解散游戏vc。有什么办法可以在不使用导航控制器的情况下解决这个问题?

This is the 1st VC: (Please pay attention to my comments below starting with "//")

这是第一个VC:(请注意我下面以“//”开头的评论)

class SelectLevelViewController: UIViewController { // I implemented a UIButton on its storyboard, and its segue shows GameViewController
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

This is the 2nd VC:

这是第二个VC:

class GameViewController: UIViewController, UIPopoverPresentationControllerDelegate {
    var scene: GameScene!
    var stage: Stage!

    var startTime = NSTimeInterval()
    var timer = NSTimer()
    var seconds: Double = 0
    var timeStopped = false

    var score = 0

    @IBOutlet weak var targetLabel: UILabel!
    @IBOutlet var displayTimeLabel: UILabel!
    @IBOutlet weak var scoreLabel: UILabel!
    @IBOutlet weak var gameOverPanel: UIImageView!
    @IBOutlet weak var shuffleButton: UIButton!
    @IBOutlet weak var msNum: UILabel!

    var mapNum = Int()
    var stageNum = Int()

    var tapGestureRecognizer: UITapGestureRecognizer!

    override func viewDidLoad() {
        super.viewDidLoad()

        let skView = view as! SKView
        skView.multipleTouchEnabled = false

        scene = GameScene(size: skView.bounds.size)
        scene.scaleMode = .AspectFill
        msNum.text = "\(mapNum) - \(stageNum)"

        stage = Stage(filename: "Map_0_Stage_1")
        scene.stage = stage
        scene.addTiles()
        scene.swipeHandler = handleSwipe

        gameOverPanel.hidden = true
        shuffleButton.hidden = true

        skView.presentScene(scene)

        Sound.backgroundMusic.play()

        beginGame()
    }

    func beginGame() {
        displayTimeLabel.text = String(format: "%ld", stage.maximumTime)
        score = 0
        updateLabels()

        stage.resetComboMultiplier()

        scene.animateBeginGame() {
            self.shuffleButton.hidden = false
        }

        shuffle()

        startTiming()
    }

    func showWin() {
        gameOverPanel.hidden = false
        scene.userInteractionEnabled = false
        shuffleButton.hidden = true

        scene.animateGameOver() {
            self.tapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideWin")
            self.view.addGestureRecognizer(self.tapGestureRecognizer)
        }
    }

    func hideWin() {
        view.removeGestureRecognizer(tapGestureRecognizer)
        tapGestureRecognizer = nil

        gameOverPanel.hidden = true
        scene.userInteractionEnabled = true

        self.performSegueWithIdentifier("win", sender: self) // this segue shows WinVC but idk where to dismiss this GameVC after WinVC gets dismissed...
    }

    func shuffle() {...}
    func startTiming() {...}
}

And this is the 3rd VC:

这是第三个 VC:

class WinVC: UIViewController {

    @IBOutlet weak var awardResult: UILabel!

    @IBAction func dismissVC(sender: UIButton) {
        self.dismissViewControllerAnimated(true, completion: {}) // dismissing WinVC here when this button is clicked
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

}

回答by Phlippie Bosman

@Ken Toh's comment was what worked for me in this situation -- call dismiss from the view controller that you want to show after everything else is dismissed.

@Ken Toh 的评论在这种情况下对我有用——在其他所有内容都被解除后,从您想要显示的视图控制器中调用解除。

If you have a "stack" of 3 presented view controllers A, Band C, where Cis on top, then calling A.dismiss(animated: true, completion: nil)will dismiss B and C simultaneously.

如果你有3个呈现视图控制器“栈” ABC,其中,C是在上面,然后调用A.dismiss(animated: true, completion: nil)将同时解雇B和C.

If you don't have a reference to the root of the stack, you could chain a couple of accesses to presentingViewControllerto get to it. Something like this:

如果您没有对堆栈根的引用,您可以链接几个访问来访问presentingViewController它。像这样的东西:

self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)

回答by Ken Toh

You can dismiss WinVC's presenting controller (GameViewController) in the completion block:

您可以在完成块中关闭 WinVC 的呈现控制器 (GameViewController):

let presentingViewController = self.presentingViewController
self.dismissViewControllerAnimated(false, completion: {
  presentingViewController?.dismissViewControllerAnimated(true, completion: {})
})

Alternatively, you could reach out to the root view controller and call dismissViewControllerAnimated, which will dismiss both modal viewcontrollers in a single animation:

或者,您可以访问根视图控制器并调用dismissViewControllerAnimated,这将在单个动画中关闭两个模态视图控制器:

self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: {})

回答by Nils Ziehn

You should be able to call:

您应该能够调用:

self.presentingViewController.dismissViewControllerAnimated(true, completion: {});

(You may need to add ?or !somewhere - I'm not a swift developer)

(您可能需要添加?!某处 - 我不是一个快速的开发人员)

回答by Rafael

Swift 5 (and possibly 4, 3 etc)

Swift 5(可能还有 4、3 等)

presentingViewController?.presentingViewController?is not very elegant and doesn't work in some instances. Instead, use segues.

presentingViewController?.presentingViewController?不是很优雅,在某些情况下不起作用。相反,使用segues.

Let's say that we have ViewControllerA, ViewControllerB, and ViewControllerC. We are at ViewControllerC(we landed here through ViewControllerA-> ViewControllerB, so if we do dismisswe will go back to ViewControllerB). We want from ViewControllerCto jump straight back to ViewControllerA.

比方说,我们有ViewControllerAViewControllerBViewControllerC。我们在ViewControllerC(我们通过ViewControllerA->到达这里ViewControllerB,所以如果我们这样做,dismiss我们将返回到ViewControllerB)。我们想从ViewControllerC直接跳回到ViewControllerA

In ViewControllerAadd the following action in your ViewController class:

ViewControllerA您的 ViewController 类中添加以下操作:

@IBAction func unwindToViewControllerA(segue: UIStoryboardSegue) {}

Yes, this line goes in the ViewController of the ViewController you want to go back to!

是的,这一行在你想要返回的 ViewController 的 ViewController 中!

Now, you need to create an exit segue from the ViewControllerC's storyboard (StoryboardC). Go ahead and open StoryboardCand select the storyboard. Hold CTRL down and drag to exit as follows:

现在,您需要从ViewControllerC的故事板 ( StoryboardC)创建退出转场。继续并打开StoryboardC并选择故事板。按住 CTRL 并拖动退出,如下所示:

enter image description here

在此处输入图片说明

You will be given a list of segues to choose from including the one we just created:

您将获得一个 segue 列表供您选择,包括我们刚刚创建的一个:

enter image description here

在此处输入图片说明

You should now have a segue, click on it:

你现在应该有一个 segue,点击它:

enter image description here

在此处输入图片说明

Go in the inspector and set a unique id: enter image description here

进入检查器并设置一个唯一的 id: 在此处输入图片说明

In the ViewControllerCat the point where you want to dismiss and return back to ViewControllerA, do the following (with the id we set in the inspector previously):

ViewControllerC您想要关闭并返回的点ViewControllerA,执行以下操作(使用我们之前在检查器中设置的 id):

self.performSegue(withIdentifier: "yourIdHere", sender: self)

回答by Mixaz

There's special unwind segueintended to roll back view stack to certain view controller. Please see my answer here: how to dismiss 2 view controller in swift ios?

有特殊的unwind segue旨在将视图堆栈回滚到某个视图控制器。请在此处查看我的答案:如何在 swift ios 中关闭 2 个视图控制器?

回答by Aaron Halvorsen

I had some animation issues when trying the accepted answer in my application. The previously presented views would flash or try to animate on the screen. This was my solution:

在我的应用程序中尝试接受的答案时,我遇到了一些动画问题。先前呈现的视图会在屏幕上闪烁或尝试动画。这是我的解决方案:

     if let first = presentingViewController,
        let second = first.presentingViewController,
            let third = second.presentingViewController {
                second.view.isHidden = true
                first.view.isHidden = true
                    third.dismiss(animated: true)

     }

回答by Andrew Foghel

Adding on to Phlippie Bosman's answer, when calling

在打电话时添加到 Phlippie Bosman 的回答

self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)

if you don't want to see (what would be the presentingViewController) you can do something like

如果你不想看到(会是什么presentingViewController),你可以做类似的事情

self.presentingViewController?.view.addSubview(self.view)

This seems a bit hacky, but so far it's been the only way I've been able to make it seem like two view controllers are dismissing in unison.

这似乎有点 hacky,但到目前为止,这是我能够让两个视图控制器看起来像是同时关闭的唯一方法。

回答by Pranit

Swift 4.0

斯威夫特 4.0

 let presentingViewController = self.presentingViewController               
 presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: false, completion: nil)

回答by Tom

Although Rafeels answer is acceptable. Not everybody uses Segue's.

虽然拉菲尔斯的回答是可以接受的。不是每个人都使用 Segue 的。

For me the following solution works best

对我来说,以下解决方案效果最好

if let viewControllers = self.navigationController?.viewControllers {
   let viewControllerArray = viewControllers.filter { 
       ##代码## is CustomAViewController || ##代码## is CustomBViewController  }

    DispatchQueue.main.async {
      self.navigationController?.setViewControllers(viewControllerArray,
                                                    animated: true)
    }
}