SpriteKitを使用してゲームを作成しています。 3つのviewControllerがあります:レベルvc、ゲームvc、および勝利vcを選択します。ゲームが終わった後、勝利vcを表示し、勝利vcで[OK]ボタンを押すと、勝利vcとゲームvcを破棄します(スタックから2つのビューコントローラをポップします)。しかし、私はそれを行う方法がわからない
self.dismissViewControllerAnimated(true, completion: {})
勝利vc(スタックの一番上)は却下されたので、ゲームvcを却下するためにどこで再度呼び出すべきかわかりません。 Navigation Controllerを使用せずにこれを修正する方法はありますか?
これが最初のVCです:(以下の「//」で始まるコメントに注意してください)
class SelectLevelViewController: UIViewController { // I implemented a UIButton on its storyboard, and its segue shows GameViewController
override func viewDidLoad() {
super.viewDidLoad()
}
}
これは2番目の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() {...}
}
そして、これは3番目の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()
}
}
@Ken Tohのコメントは、この状況で私にとってうまくいったものでした-他のすべてが却下された後に表示したいView Controllerからdismissを呼び出します。
3つの表示されたView Controller A
、B
、およびC
の「スタック」があり、C
が一番上にある場合、A.dismiss(animated: true, completion: nil)
はBとCを同時に却下します。
スタックのルートへの参照がない場合は、presentingViewController
へのアクセスを数回連鎖して取得できます。このようなもの:
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
完了ブロックでWinVCの表示コントローラー(GameViewController)を閉じることができます:
let presentingViewController = self.presentingViewController
self.dismissViewControllerAnimated(false, completion: {
presentingViewController?.dismissViewControllerAnimated(true, completion: {})
})
または、ルートView ControllerにアクセスしてdismissViewControllerAnimatedを呼び出すと、単一のアニメーションで両方のモーダルViewControllerが閉じられます。
self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: {})
あなたが呼び出すことができるはずです:
self.presentingViewController.dismissViewControllerAnimated(true, completion: {});
(?
または!
をどこかに追加する必要があるかもしれません-私はSwift開発者ではありません)
ビュースタックを特定のView Controllerにロールバックするための特別なアンワインドセグエがあります。ここで私の答えを参照してください: 2つのView ControllerをSwift ios?
私のアプリケーションで受け入れられた答えをしようとすると、アニメーションの問題がいくつかありました。以前に表示されたビューが点滅するか、画面上でアニメーション化されます。これが私の解決策でした:
if let first = presentingViewController,
let second = first.presentingViewController,
let third = second.presentingViewController {
second.view.isHidden = true
first.view.isHidden = true
third.dismiss(animated: true)
}
Swift 5(および場合によっては4、3など)
presentingViewController?.presentingViewController?
はあまりエレガントではなく、場合によっては機能しません。代わりに、segues
を使用します。
ViewControllerA
、ViewControllerB
、およびViewControllerC
があるとします。 ViewControllerC
にいます(ViewControllerA
-> ViewControllerB
でここに着陸したので、dismiss
を実行すると、ViewControllerB
に戻ります)。 ViewControllerC
からViewControllerA
にジャンプして戻りたい。
ViewControllerA
で、ViewControllerクラスに次のアクションを追加します。
@IBAction func unwindToViewControllerA(segue: UIStoryboardSegue) {}
はい、この行は戻りたいViewControllerのViewControllerに入ります!
ここで、ViewControllerC
のストーリーボード(StoryboardC
)から出口セグエを作成する必要があります。先に進み、StoryboardC
を開いて、ストーリーボードを選択します。 Ctrlキーを押しながらドラッグして、次のように終了します。
作成したセグエを含むセグエのリストが表示されます。
これでセグエが表示されます。クリックしてください:
ViewControllerC
を閉じてViewControllerA
に戻るポイントで、次の操作を行います(以前にインスペクターで設定したIDを使用)。
self.performSegue(withIdentifier: "yourIdHere", sender: self)
電話するとき、Phlippie Bosmanの答えに追加
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
表示したくない場合(presentingViewController
になります)、次のようなことができます
self.presentingViewController?.view.addSubview(self.view)
これは少しハッキーに思えますが、これまでのところ、2つのView Controllerが一斉に却下されているように見せることができた唯一の方法でした。
Rafeelsの回答は受け入れられますが。誰もがセグエを使用しているわけではありません。
私にとっては、次のソリューションが最適です
if let viewControllers = self.navigationController?.viewControllers {
let viewControllerArray = viewControllers.filter {
$0 is CustomAViewController || $0 is CustomBViewController }
DispatchQueue.main.async {
self.navigationController?.setViewControllers(viewControllerArray,
animated: true)
}
}
Swift 4.
let presentingViewController = self.presentingViewController
presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: false, completion: nil)