【Swift】Swift入門 ~ NavigationControllerを使ってみる ~

2020.02.05

どうも、むつたくです。
今回も前回に続き、Swiftになります。今回の内容はNavigationControllerについてです。

前回の記事→【Swift】Swift入門 ~ UITableViewを使ってみる ~

 

NavigationControllerは、複数あるViewControllerを階層的に管理し、画面間を簡単に行き来(ナビゲーション)することができるコントローラになります。
前の画面に戻ることができるボタンを自動配置してくれますし、タイトルも設定することができます。このコントローラも便利だと思います。

 

今回やること

  • NavigationControllerについて
  • NavigationControllerの簡単な使い方
  • NavigationControllerの配置
  • Segueを使用した遷移
  • Segueを使用しない遷移

 

開発環境

  • macOS Catalina(10.15.1)
  • Xcode 11.3
  • Swift 5.1
  • Simulater iPhone 11Pro
  • iOS 13.3

 

NavigationController について

NavigationControllerは、冒頭でも説明しましたが、ViewControllerを管理、画面間を行き来するコントローラです。iPhoneの設定アプリ等にも使用されてます。下部画像の赤枠線の部分で、ナビゲーションバーと言います。

 

ナビゲーションバーの左側をタップすれば、前画面に戻ることもできますし、もちろん右にスワイプでも戻ることが出来ます。また、遷移された画面は、NavigationControllerの管理下になり、スタックされていきます。
では、早速使用していきましょう。

 

NavigationController の簡単な使い方

タイトル設定

タイトルを設定するには、以下のコードになります。

1
    title = "*************"

[viewDidLoad]に記載すれば問題ないでしょう。

 

戻るボタンのテキスト非表示

テキストを非表示にするには、遷移元の画面で以下のコードを記載します。

1
    navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)

[UIBarButtonItem]のtitleに空文字を設定します。こちらも[viewDidLoad]に記載すれば問題ないでしょう。
また、StoryBordでやる場合は、同様の項目に半角スペースを設定しないといけません。

 

n画面前に戻る

1つ前や、2つ前、はたまた一番最初の画面に戻りたい場合です。

1
2
3
4
5
6
7
8
9
    // 1つ前 に戻る場合
    navigationController?.popViewController(animated: true)

    // 2つ前 に戻る場合
    let index = navigationController!.viewControllers.count - 3
    navigationController?.popToViewController(navigationController!.viewControllers[index], animated: true)

    // 一番最初 に戻る場合
    navigationController?.popToRootViewController(animated: true)

1つ前、一番最初の画面に戻りたい場合は、簡単に実装できますが、2つ以上前の画面に戻る場合は、スタックされた画面数から戻る画面数+1の減算してあげればOKです。

 

ナビゲーションバーを非表示にする

非表示にさせたい画面で、以下のコードを記載します。

1
    navigationController?.navigationBar.isHidden = true

ただ、これを実装した場合、全ての画面で非表示になってしまうので、他の画面では、以下のコードを実装すると再表示されます。

1
2
3
    override func viewWillAppear(_ animated: Bool) {
        navigationController?.navigationBar.isHidden = false
    }

 

NavigationController の配置

ViewControllerに設定

さて、前回は記事では、TavleViewのセルをタップしたら、コンソールにタップした行情報をprint()する処理まで実装しました。今回はそこにNavigationControllerを配置します。
配置するには、まずは配置したいViewControllerを選択します。
次に、[ メニューバー > Editer > Embed In > Navigation Controller ]を順に選択して行くと、指定したViewControllerに配置出来ます。

 

これでNavigationControllerの配置は完了です。
ついでに初期画面のナビゲーションのタイトルを表示してみましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ViewController.swift

    override func viewDidLoad() {
        super.viewDidLoad()

        // ↓追加
        title = "駅リスト"
       
        // <TableView初期設定>
        tableView.frame = view.frame
        tableView.dataSource = self
        tableView.delegate = self
        tableView.tableFooterView = UIView(frame: .zero)

    }

 

title = “” でNavigationControllerのタイトルを設定することができます。実行してみましょう。以下のイメージになるかと思います。

 

画面遷移

Segueを使用した遷移

次は、画面遷移です。まずはSegueを使用した遷移方法からです。
使用するのは、画面遷移に必要な「Segue」、画面遷移を起動する「performSegue」、Segueを使用した画面遷移を検知する「prepare」の3つになります。

 

まずは、新しいswiftファイルを作成します。「Cocoa Touch Class > (class:)SecondViewController > (Subclass:)UIViewContoller」で作成していきます。

 

次に、新しいViewControllerをMain.StoryBoardに配置します。配置したら、先ほど作成したswiftファイルと紐付けるため、Identity inspectorのCustomClassを編集します。同様に、IdentityのStoryStoryboard IDも編集し、「Use Storyboard ID」のチェックをOnします。

 

そうしましたら、TableViewCellを選択して、Controlキーを押しながら、SecondViewにドラッグ&ドロップします。ドロップした先でいくつか選択肢が表示されましたが、今回はNavigationControllerを使用した階層的に管理しているので、「Selection Segue > Show」を選択します。

 

これで完了です。Buildして実行してみましょう。テーブルセルをタップするとSecondViewと表示された画面に遷移すると思います。ブログ冒頭で記載した様に戻る際は左上の「Back」で前画面に戻ることも出来ますし、右にスワイプでも可能です。

 

親から子への値渡し

ここからは、コードを書いていく必要があります。また、Segueの種類を変更しなくてはいけないので、Segueを削除します。
まずは、Segueの設定からです。MainのViewController->SecondViewControllerのSegueを削除します。
次に、新しいSegueを作成しますが、コード側で任意のタイミングで遷移させたいので「Manuel Segue > Show」を選択します。

 

それから、そのSegueをコードから呼び出すのでIndentityを設定します。「showSecondView」とします。

 

次に、「SecondViewController」です。Labelに親から受け取った駅名を表示したいので、受け取る変数と、変数をLabelのTextに格納する処理を記載します。画像は省きますが、StoryBoardのLabelとSecondViewController.swiftを紐付けてあげて下さい。

1
2
3
4
5
6
7
8
9
10
11
12
13
// SecondViewController.swift
    // 親から受け取る変数
    var getName: String = ""

    @IBOutlet weak var stationName: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
       
        // Labelへ格納
        self.stationName.text = getName

    }

 

次は、「ViewController」です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ViewController.seift

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
   
    // ↓追加
    private var stationName: String = ""

    // ↓追加
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "showSecondView") {
            let secondVC = segue.destination as! SecondViewController
            secondVC.getName = self.stationName
        }
    }

//...以下省略...
}

 

8行目の変数には、タップされた時にタップ行の駅名を格納します。
11行目の関数[prepare]は、Segueが動作すること(画面遷移)をViewControllerに通知する役割になります。遷移先のControllerを定義し、そのControllerのパブリック変数にタップ行の駅名を格納する処理になります。
ここで注意してほしい事があり、現状は1本しかSegueを使用していないので、if文での分岐は必要ないですが、複数本使用する場合には必ず分岐をさせないと誤った画面遷移になりますので、分岐を忘れない様にして下さい。

 

次にTableViewのDelegateです。print()は必要ないので削除してあります。

1
2
3
4
5
6
// ViewController.swift
    // セルタップ時のイベント
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.stationName = tableData[indexPath.section][indexPath.row]
        performSegue(withIdentifier: "showSecondView",sender: nil)
    }

 

5行目で、画面遷移を実行させてますが、StoryBoardで設定した「showSecondView」のSegueを起動し画面遷移、その間に関数「prepare」がSegueの起動を検知したので、発火した…と言う流れになります。

 

これが、Segueを使用した画面遷移になります。必要なのは、StoryBoardでSegueを引っ張って、そのSegueにIdentityを設定、どこぞのイベントで画面遷移処理のここでは「performSegue」を使用する。値渡しがある場合は、「prepare」の引数[segue]を使用して値を設定する必要あり…と言った感じで、処理があっちこっちになるので、ちょっと管理が大変かもしれません。

 

Segueを使用しない画面遷移

次は、Segueを使用しない画面遷移になります。使用するものはNavigationControllerの「pushViewController」の1つです。

 

StoryBoardにNavigationControllerが配置された状態からスタートします。
swiftファイルで完結します。TableViewのタップイベントに以下のコードを記載します。

1
2
3
4
5
6
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let stationName = tableData[indexPath.section][indexPath.row]
        let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "SecondView") as! SecondViewController
        secondVC.getName = stationName
        self.navigationController?.pushViewController(secondVC, animated: true)
    }

 

3行目で、遷移先のViewControllerを定義します。instantiateViewControllerの引数[withIdentifier]には遷移先のStoryboardIDを記載します。
5行目で、NavigationControllerの[pushViewController]を使用して遷移させます。

 

結果は、Segueを使用した画面遷移と同じになりますが、簡単に実装でき、コード量もこちらがスッキリします。ただ、StoryBoard上での確認はSegueが無いので出来ず、コードから探す事になるので、複数画面がある場合は、初めて見る方には、ちょっと管理が大変かもしれません。

 

まとめ

Segueを使用した画面遷移は、視覚的にわかりやすいメリットはありますが、StoryBoardもSwiftファイルもゴニョゴニョしなければいけないと言うデメリットもあります。
Segueを使用しない画面遷移は、StoryBoardの各オブジェクトにIDを割り当てるぐらい、コード量も比較的少なく済み時短にも繋がるメリットはありますが、視覚的に分かりづらい、様々なSwiftファイルを追っかけないといけないと言うデメリットもあります。
どちらも一長一短ですが、ケースバイケースなのかなと思ってます。

 

と言う事で、今回はNavigationControllerについて紹介していきました。
次回もSwiftの入門記事を書く予定です。
それでは、またの機会に!


Top