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
Dismiss more than one view controller simultaneously
提问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
, B
and C
, where C
is on top, then calling A.dismiss(animated: true, completion: nil)
will dismiss B and C simultaneously.
如果你有3个呈现视图控制器“栈” A
,B
和C
,其中,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 presentingViewController
to 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 dismiss
we will go back to ViewControllerB
). We want from ViewControllerC
to jump straight back to ViewControllerA
.
比方说,我们有ViewControllerA
,ViewControllerB
和ViewControllerC
。我们在ViewControllerC
(我们通过ViewControllerA
->到达这里ViewControllerB
,所以如果我们这样做,dismiss
我们将返回到ViewControllerB
)。我们想从ViewControllerC
直接跳回到ViewControllerA
。
In ViewControllerA
add 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 StoryboardC
and select the storyboard. Hold CTRL down and drag to exit as follows:
现在,您需要从ViewControllerC
的故事板 ( StoryboardC
)创建退出转场。继续并打开StoryboardC
并选择故事板。按住 CTRL 并拖动退出,如下所示:
You will be given a list of segues to choose from including the one we just created:
您将获得一个 segue 列表供您选择,包括我们刚刚创建的一个:
You should now have a segue, click on it:
你现在应该有一个 segue,点击它:
Go in the inspector and set a unique id:
In the ViewControllerC
at 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)
}
}