Table View からの画面遷移 (Swift)

前回は 「 Table View Cell をカスタマイズする方法 」 で、Table View Cell をカスタマイズする方法についてご説明しました。

今回はセルをタップした時に、次のような感じで Table View の画面から詳細画面に画面遷移して、選択された動物のデータを表示する方法をご説明します。

Table View からの画面遷移1

前回の続きのプロジェクトを使って、アウトレットの生成方法などはわかっている前提で進めますので、もしわからない方は Table View の使い方Table View Cell をカスタマイズする方法 をご覧ください。

Navigation Controller に組み込む

Navigation Controller とは?

Navigation Controller はナビゲーションスタックという View Controller のスタックを保持していて、画面遷移を管理してくれるコントローラーです。

Navigation Controller に組み込むと、View Controller の上にナビゲーションバーが自動的に追加され、back ボタンなども自動的に追加してくれます。

今回はやりませんが、ナビゲーションバーに Bar Button Item を配置して、追加・削除・編集・キャンセル・保存などのボタンを追加することもできます。


View Controller を Navigation Controller に組み込む

それでは、Table View の View Controller を Navigation Controller に組み込んでみましょう。

View Controller を選択した状態で、エディターエリア右下の Embed In ボタンをクリックし、Navigation Controller を選択します。

Table View からの画面遷移2

そうすると、次のように View Controller が Navigation Controller に組み込まれます。

Table View からの画面遷移3


詳細画面 (DetailViewController) を作る

DetailViewController クラスを作る

まずは、詳細画面の View Controller 用ののクラスをつくります。

メニューバーの File > New > File... で iOS の Cocoa Touch Class を選択し Next をクリックして、Class に DetailViewController、Subclass of に UIViewController を選択しファイルを生成します。

Table View からの画面遷移9


DetailViewController を追加しクラスを設定する

Table View から画面遷移して表示される詳細画面を作ります。

右上の➕ボタンをクリックしてオブジェクトライブラリーを表示し、View Controller を探して、Table View の View Controller の右横にドラッグ&ドロップします。

Table View からの画面遷移4


追加した ViewController を選択した状態で、右側のユーティリティエリアの Identity インスペクターを選択します。

上のほうにある Custom Class のクラスの Class のドロップダウンリストから DetailViewController を選んでおきます。

Table View からの画面遷移10

DetailViewController にオブジェクトを配置する

新しく作った View Controller に Image View と Label を配置していきます。

位置・大きさ・コンストレイントなどの値を一応書いておきますが、きっちりこの通りでなくてもだいたいで大丈夫です。


まず、オブジェクトライブラリーから Image View をだいたい表示したい場所に配置したら、コンストレイントを追加します。

Table View からの画面遷移5

Table View からの画面遷移6

  • Spacing to nearest neighbor - 上: 20
  • Width: 300
  • Height: 300
  • Alignment: Horizontally in Container

Attributes inspector の Image で実際の画像を選んでおくと、出来上がりがわかりやすいです。

Table View からの画面遷移7


同じような要領で、Label を以下のように4つ追加します。

Table View からの画面遷移8

  • Text: 日本語のなまえ
  • Color: Dark Gray Color
  • Spacing to nearest neighbor - 上: 30
  • Width: 300
  • Alignment: Horizontally in Container
  • Text: ふくろう
  • Color: Dark Gray Color
  • Font: Helvetica Bold 28.0
  • Spacing to nearest neighbor - 上: 10
  • Width: 300
  • Alignment: Horizontally in Container
  • Text: 英語のなまえ
  • Color: Dark Gray Color
  • Spacing to nearest neighbor - 上: 30
  • Width: 300
  • Alignment: Horizontally in Container
  • Text: Owl
  • Color: Dark Gray Color
  • Font: Helvetica Bold 28.0
  • Spacing to nearest neighbor - 上: 10
  • Width: 300
  • Alignment: Horizontally in Container

DetailViewController のアウトレットを生成する

次に DetailViewController のアウトレットを生成します。

ストーリーボードで、DetailViewController の中のふくろうの Image View など選択した状態で、メニューから Editor > Assistant Editor を選択するか、Adjust Editor Options ボタンの Assistant から Assistant Editor を開きます。

Assistant Editor が開いたら、開かれたファイルが DetailViewController.swift であることを確認してください。

違う場合は、Assistant Editor の上の Automatic をクリックして、DetailViewController.swift に変更してください。

Table View からの画面遷移11


そして、画像の Image View と「ふくろう」「Owl」のラベルから、それぞれ ⌃ Control キーを押しながら DetailViewController クラスにドラッグ&ドロップして、以下のように 3 つのアウトレットを生成しておいてください。

Table View からの画面遷移12

@IBOutlet weak var animalImageView: UIImageView!
@IBOutlet weak var animalNameJPLabel: UILabel!
@IBOutlet weak var animalNameENLabel: UILabel!

画面を Segue でつなぐ

Segue はストーリーボードで二つの View Controller 間の画面遷移を定義するものです。

今回は Table View Cell をタップした時に、詳細画面に遷移するように Segue を生成します。


まず、ストーリーボードで Table View 内の AnimalTableViewCell を選択してください

⌃ Control キーを押しながら Detail View Controller にドラッグして離すと、Segue の種類を選ぶポップアップが出てきますので、Show を選択します。

Table View からの画面遷移13

Table View からの画面遷移14

ストーリーボードに Segue が表示されて、Detail View Controller のほうにも上に Navigation Item が追加されます。

この Show segue が実行されると、AnimalTableViewCell をタップした時に、Navigation Controller のもっているナビゲーションスタックに Detail View Controller がプッシュされて、元の View Controller の上にモーダルで表示されます。


あとでコードから Segue を特定するのに使うので、Segue を選択して、Attributes inspector の Storyboard Segue の Identifier に showDetailSegue と設定しておいてください。

Table View からの画面遷移15

prepare で詳細画面にデータ渡す

セルがタップされた時に、タップされた動物データを詳細画面に渡すようにします。

DetailViewController.swift ファイルを開いて、Animal 型の animal という変数を定義します。

Table View の View Controller から画面遷移する際にこの animal に値を設定して、viewDidLoad() で、その animal の画像や名前を Image View や Label にそれぞれ設定します。

Table View からの画面遷移16

import UIKit

class DetailViewController: UIViewController {

    var animal: Animal!
    
    @IBOutlet weak var animalImageView: UIImageView!
    @IBOutlet weak var animalNameJPLabel: UILabel!
    @IBOutlet weak var animalNameENLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        animalImageView.image = UIImage(named: animal.imageName)
        animalNameJPLabel.text = animal.nameJP
        animalNameENLabel.text = animal.nameEN
    }
    
}

続いて ViewController.swift ファイルを開いて、prepare() という名前のメソッドを追加します。

Table View からの画面遷移17

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "showDetailSegue" {
        if let indexPath = myTableView.indexPathForSelectedRow {
            guard let destination = segue.destination as? DetailViewController else {
                fatalError("Failed to prepare DetailViewController.")
            }
            
            destination.animal = animals[indexPath.row]
        }
    }
}

prepare() は Segue が実行される前に呼ばれるメソッドで、ここで次の view controller が表示される前にやりたいことをここで実行することができます。

ここでは実行される segue の identifier が showDetailSegue の時に、destination の DetailViewController を取得して、その animal にタップされた indexPath の animal オブジェクトを設定しています。


これで画面遷移と詳細画面にデータを渡すところは完了ですが、このままだと一度詳細画面にいって、戻ってきた時にタップされたセルが反転したままになってしまいます。

Table View からの画面遷移18

これをなおすには、次のコードをViewController クラスに追加してください。

override func viewWillAppear(_ animated: Bool) {
    if let indexPath = myTableView.indexPathForSelectedRow{
        myTableView.deselectRow(at: indexPath, animated: true)
    }
}

この View Controller が再度表示される時に viewWillAppear() メソッドが呼ばれ、セルの選択が解除 (deselect) されます。


念のため、ViewController.swift の全部のコードを載せておきます。

import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var animals: [Animal] = []
    
    @IBOutlet weak var myTableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        myTableView.dataSource = self
        myTableView.delegate = self
        
        loadData()
    }
    
    func loadData() {
       animals.append(Animal(nameJP: "ふくろう", nameEN: "Owl", imageName: "owl"))
       animals.append(Animal(nameJP: "とり", nameEN: "Bird", imageName: "bird"))
       animals.append(Animal(nameJP: "らいおん", nameEN: "Lion", imageName: "lion"))
       animals.append(Animal(nameJP: "かば", nameEN: "Hippo", imageName: "hippo"))
       animals.append(Animal(nameJP: "くま", nameEN: "Bear", imageName: "bear"))
       animals.append(Animal(nameJP: "はりねずみ", nameEN: "Hedgehog", imageName: "hedgehog"))
       animals.append(Animal(nameJP: "ぞう", nameEN: "Elephant", imageName: "elephant"))
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return animals.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        guard let cell = myTableView.dequeueReusableCell(withIdentifier: "AnimalTableViewCell", for: indexPath) as? AnimalTableViewCell else {
            fatalError("Dequeue failed: AnimalTableViewCell.")
        }
     
        cell.animalNameJPLabel.text = animals[indexPath.row].nameJP
        cell.animalNameENLabel.text = animals[indexPath.row].nameEN
        cell.animalImageView.image = UIImage(named: animals[indexPath.row].imageName)
    
        return cell
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetailSegue" {
            if let indexPath = myTableView.indexPathForSelectedRow {
                guard let destination = segue.destination as? DetailViewController else {
                    fatalError("Failed to prepare DetailViewController.")
                }
                
                destination.animal = animals[indexPath.row]
            }
        }
    }
    
    override func viewWillAppear(_ animated: Bool) {
        if let indexPath = myTableView.indexPathForSelectedRow{
            myTableView.deselectRow(at: indexPath, animated: true)
        }
    }
}

ナビゲーションバーのタイトルと戻るボタンを設定する

ナビゲーションバーにこのアプリのタイトル「どうぶつ図鑑」を設定して、詳細画面からリスト画面に戻るボタンを「もどる」に変更してみましょう。


Storyboard を表示して、Table View の View Controller のナビゲーションバーをクリックします。

右側で Attribute inspector を表示して Navigation Item の Title に「どうぶつ図鑑」と入力します。

Table View からの画面遷移19

詳細画面の back の文字も「どうぶつ図鑑」になってしまうので、Title の下にある Back Button に「もどる」を設定します。

Table View からの画面遷移20


ビルドしてシミュレーターで実行する

それでは、ビルドして実行してみましょう。

ツールバー左側の ボタンをクリックすると、選択されているシミュレータが立ち上がり、アプリがインストールされて実行されます。

Table View からの画面遷移21

Table View からの画面遷移22

リスト画面でタップされた動物が詳細画面に表示されましたね。


以上、Table View から詳細画面へ画面遷移する方法についてご説明しました。

© 2024 iOS 開発入門