iOS swift プログラミング

NavigationControllerとViewControllerの遷移/値の渡し方/受け取り方/戻り方まとめ

更新日:




SwiftでiOSアプリを開発していると、画面遷移と値の受け渡しに無茶苦茶苦戦します。Androidだとあんなに簡単なのに。。。と度々絶望する日々。と言うことで、色んなパターンの画面遷移方法をまとめておきました。ソースもgithub上にありますのでご活用ください。

 

Swift: 4.0.3

Xcode: 9.2

iOS: 11.2

ソース:
https://github.com/yheihei/ios/tree/master/MoveViewTutorial

下記4つを説明する。

  • UINavigationControllerへの遷移(StoryBoardから)と値の受け渡し方/戻し方
  • UINavigationControllerへの遷移(コードから)と値の受け渡し方/戻し方
  • UIViewControllerへの遷移(StoryBoardから)と値の受け渡し方/戻し方
  • UIViewControllerへの遷移(コードから)と値の受け渡し方/戻し方

UINavigationControllerへの遷移(StoryBoardから)と値の受け渡し方/戻し方

作りたい遷移はこの部分。

NavigationControllerへの遷移と値の受け渡し方

本章では、StoryBoardを使って、UINavigationControllerがついたViewControllerに値を渡して画面遷移し、値を元の画面に戻すまでをやる。下記の様な感じ。

まず値を渡して。

値を前画面に戻す。

 

それでは実装する。

次画面のUINavigationControllerへの矢印を引く(segue)

NavigationControllerへのstoryboardからの遷移

SegueのIdentifierを命名する

segueにidentifierをつける

 

次画面のViewControllerに値がセットされる変数を書く

NavitukiViewController.swift

class NavitukiViewController: UIViewController {
    var receiveText:String? // 前画面からのテキストがここに入る

 

前画面のprepareで渡したい値を設定する

TopViewController.swift

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let identifier = segue.identifier else {
            // identifierが取れなかったら処理やめる
            return
        }
        
        if(identifier == "ncSegue") {
            // NavigationControllerへの遷移の場合
            
            // segueから遷移先のNavigationControllerを取得
            let nc = segue.destination as! UINavigationController
            
            // NavigationControllerの一番目のViewControllerが次の画面
            let vc = nc.topViewController as! NavitukiViewController
            
            // 次画面のテキスト表示用のStringに、本画面のテキストフィールドのテキストを入れる
            vc.receiveText = self.sendingTextField.text
        }
    }

 

ここまでで、下記の様にNavigationControllerへ値を渡すことができる。

 

次画面から前画面に値を通知してやる

次は、前画面に値を戻してやる。

まずは「Done」ボタンが押された時のIBActionを設定する。

 

前画面の値を更新しつつ画面を閉じる

NavitukiViewController.swift

    @IBAction func done(_ sender: Any) {
        // 表示の大元がViewControllerかNavigationControllerかで戻る場所を判断する
        if self.presentingViewController is UINavigationController {
            //  表示の大元がNavigationControllerの場合
            let nc = self.presentingViewController as! UINavigationController

            // 前画面のViewControllerを取得
            let vc = nc.topViewController as! TopViewController

            // 前画面のViewControllerの値を更新
            vc.receivedTextLabel.text = self.returnTextField.text

            // 今の画面を消して、前画面を表示させる<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>
            self.dismiss(animated: true, completion: nil)
            
        }
    }<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>

 

キャンセルの場合に画面を閉じる処理

キャンセルボタンのIBActionを設定。

 

presentingViewControllerを使って、表示の大元を調べ、画面の消し方を変える。

NavitukiViewController.swift

    @IBAction func close(_ sender: Any) {
       // 表示元がViewControllerかNavigationControllerかで消し方が違う
        if self.presentingViewController is UINavigationController {
            //  表示元がNavigationControllerの場合 (★<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>今回こっちを通る)
            self.dismiss(animated: true, completion: nil)
        } else {
            // 表示元がViewControllerの場合
            self.navigationController?.popViewController(animated: true)
        }
    } 

 

 

UINavigationControllerへの遷移(コードから)と値の受け渡し方/戻し方

次にStoryBoardを使わず、コードからNavigationControllerへ遷移させてみる。

 

Button押下時のIBAction設定

 

UINavigationControllerをコードから起動。次画面に値を渡す

NavigationControllerのStoryBoard IDを設定。

NavigationControllerのidentifier設定

 

ボタンが押下されたときに開くNavigationControllerを指定して表示。値も渡す。

TopViewController.swift

 

    @IBAction func moveNC(_ sender: Any) {
        let storyboard: UIStoryboard = self.storyboard!
        // 設定したidentifier名でNavigationControllerを取得
        let nc = storyboard.instantiateViewController(withIdentifier: "navigationController") as! UINavigationController
        
        // NavigationControllerの一番目のViewControllerが次の画面
        let vc = nc.topViewController as! NavitukiViewController
        
        // 次画面のテキスト表示用ラベルのテキストを、本画面のテキストフィールドのテキストに
        vc.receiveText = self.sendingTextField.text
        
        // NavigationControllerを表示(NCのトップのViewControllerが表示される)
        self.present(nc, animated: true, completion: nil)
    }

 

次画面から前画面に値を渡す

同じ。

 

UIViewControllerに遷移(StoryBoardから)と値の受け渡し方/戻し方

ViewControllerからViewControllerへStoryBoardで遷移し、値の受け渡しをする。

最終的にはこんな感じの動きになる。

 

 

 

最初の画面から次のViewControllerへsegueを設定

 

2番目の画面から3番目の画面に遷移させつつ、値もsegueで渡す

StoryBoardからsegueを設定。

 

Segueのidentifierを命名する。

segueにidentifierをつける

 

prepareで値を渡して、表示する。

SingleViewController.swift

 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let identifier = segue.identifier else {
            // identifierが取れなかったら処理やめる
            return
        }
        
        if(identifier == "vcToNCTukiVC") {
            // NCつきViewControllerへの遷移の場合
            
            // segueから遷移先のViewControllerを取得
            let vc = segue.destination as! NavitukiViewController
            
            // 次画面のテキスト表示用ラベルのテキストを、本画面のテキストフィールドのテキストに
            vc.receiveText = self.sendingTextField.text
        }
    }

 

次画面からCancelで前画面に戻る

presentingViewControllerで表示元のControllerが取得できる。

表示元がUIViewControllerなので、self.navigationController?.popViewController(animated: true)で消す。

NavitukiViewController.swift

 

    @IBAction func close(_ sender: Any) {
       // 表示元がViewControllerかNavigationControllerかで消し方が違う
        if self.presentingViewController is UINavigationController {
            //  表示元がNavigationControllerの場合
            self.dismiss(animated: true, completion: nil)
        } else {
            // 表示元がViewControllerの場合
            self.navigationController?.popViewController(animated: true)
        }
    }  

 

次画面から前画面に値を戻す

presentingViewControllerで前の画面が何かを調べられる。前の画面がViewControllerだった場合の遷移を追加し、戻す値を設定してやる。

NavitukiViewController.swift

    @IBAction func done(_ sender: Any) {
        // 表示の大元がViewControllerかNavigationControllerかで戻る場所を判断する
        if self.presentingViewController is UINavigationController {
            //  表示の大元がNavigationControllerの場合
            let nc = self.presentingViewController as! UINavigationController
            let vc = nc.topViewController as! TopViewController
            vc.receivedTextLabel.text = self.returnTextField.text
            self.dismiss(animated: true, completion: nil)
            
        } else {
            // 表示元がViewControllerの場合
            // 前画面のViewControllerを取得
            let count = (self.navigationController?.viewControllers.count)! - 2
            let vc = self.navigationController?.viewControllers[count] as! SingleViewController
            vc.receivedTextLabel.text = self.returnTextField.text
            // 画面を消す
            self.navigationController?.popViewController(animated: true)
        }
    }

完成。

 

UIViewControllerへの遷移(コードから)と値の受け渡し方/戻し方

最後にUIViewControllerへの遷移と値の受け渡しをコードからやってみる。

 

最初の画面から次のViewControllerへ遷移

まず次の画面にStoryBoard IDを設定。

StoryBoardIDを設定

 

設定したStoryBoard IDを元にViewControllerを取得、遷移させる。

TopViewController.swift

    @IBAction func moveVC(_ sender: Any) {
        let storyboard: UIStoryboard = self.storyboard!
        // 設定したidentifier名で次画面のViewControllerを取得
        let vc = storyboard.instantiateViewController(withIdentifier: "singleVC") as! SingleViewController
        
        // 次画面のViewControllerを表示
        self.navigationController?.pushViewController(vc, animated: true)
    }<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>

 

2番目のViewControllerから3番目のViewControllerに値を渡しつつ遷移

3番目のViewControllerにStoryBoard IDをつける。

 

3番目のViewControllerに値を渡しつつ遷移する。

SingleViewController.swift

    @IBAction func moveNabitukiVC(_ sender: Any) {
        let storyboard: UIStoryboard = self.storyboard!
        // 設定したidentifier名で次画面のViewControllerを取得
        let vc = storyboard.instantiateViewController(withIdentifier: "navitukiView") as! NavitukiViewController
        
        // 次画面のテキスト表示用ラベルのテキストを、本画面のテキストフィールドのテキストに
        vc.receiveText = self.sendingTextField.text
        
        // 次画面のViewControllerを表示
        self.navigationController?.pushViewController(vc, animated: true)
    }

 

次画面から前画面に値を戻す

同じ。

 

ポイント

  • StoryBoardの遷移時の値の受け渡しにはsegueを使う。segueにidentifierをつけ、prepare時にidentifierにより処理を分岐させる
  • コードからの遷移は、self.present、NavigationControllerが付いていれば self.pushViewController
  • self.presentingViewControllerで起動元のViewControllerが取得できる。値を前画面に戻す時などによく使う

 

ソースコードはgithubにあるので、詳しくはそちらを試してみてほしい。

github:

https://github.com/yheihei/ios/tree/master/MoveViewTutorial



-iOS, swift, プログラミング

Copyright© バイラシー , 2018 All Rights Reserved.