【iOS】iOSアプリ開発入門~ 画面遷移編1~

はじめに

前回は条件分岐など少しプログラミング的な処理を入れてUIを更新しする方法ついて投稿しました。
SwiftとUIの接続編3:https://naoyalog.com/%e3%80%90ios%e3%80%91ios%e3%82%a2%e3%83%97%e3%83%aa%e9%96%8b%e7%99%ba%e5%85%a5%e9%96%80-swift%e3%81%a8ui%e3%81%ae%e6%8e%a5%e7%b6%9a%e7%b7%a8%ef%bc%93/

基本的なアプリには画面がいくつかあります。
今回は画面を追加し、アプリを作る上で必須となる「画面遷移」について説明します。

少しプログラミングの話も出てくるかと思うので一度こちらの記事に目を通しておくといいかもしれません。

それではプロジェクトを開きます。
前回までで処理やUIが少し増えたので今回は新しいプロジェクトを作って進めます。
もちろん前回までのプロジェクトを使って頂いても構いません。

画面を追加する

遷移先画面用のファイルを追加する

まず画面遷移するためには遷移先の画面が必要です。
画面を作るためにはSwiftファイルとStoryboardのファイルが必要になります。
遷移先の画面はSecondViewControllerという名前にしてファイルを作っていきましょう。

まずXcodeから追加先のフォルダを右クリックします。
メニューが表示されるので[New File…]を選択します。

スクリーンショット 2020-05-26 23.12.59.png

まずSwiftファイルを作ります。
表示されたポップアップから[Swift File]を選択し[Next]をクリックします。

スクリーンショット 2020-05-26 23.17.00.png

[Save As:]に作りたいファイル名を拡張子なしで入力し[Create]をクリックします。

スクリーンショット 2020-05-26 23.19.47.png

SecondViewController.swiftが作成されました。
同じ手順でStoryboardファイルも作成します。

スクリーンショット 2020-05-26 23.25.02.png
スクリーンショット 2020-05-26 23.26.05.png

SecondViewController.storyboardが作成されました。

これでファイルの準備は完了です。

スクリーンショット 2020-05-26 23.28.52.png

画面クラスを作成する

画面を表示するためにはまず画面用のクラスが必要です。
クラス名をSecondViewControllerとして以下のようにSecondViewController.swiftに作成します。
ちなみにファイル名とその中に定義するクラス名は必ずしも一致している必要はありません。
ですがファイルを見ればどのクラスが書かれたファイルなのかすぐわかるように一致させることをおすすめします。

import UIKit

class SecondViewController: UIViewController {

}

これで画面のクラスは作成できました。
このコードについて簡単に説明します。

まずclass SecondViewControllerは定義するクラス名を表します。
このあたりは別記事の説明を参照してください。

クラス名に:を付けてUIViewControllerと書かれています。
これは継承といい、オブジェクト指向の考え方の1つです。
継承とはあるクラスをベースとして新しいクラスを作成する方法です。
継承元の特性を引き継がせるようなイメージです。拡張しているといってもいいかもしれません。
この段階ではSecondViewControllerにはプロパティもメソッドも持っていないのでUIViewControllerとほぼ同じ特性を持つクラスです。

UIViewControllerは全ての画面のベースとなるクラスです。
表示する画面となるViewや画面遷移のメソッドなどを持っています。
プロジェクト作成時に自動生成されたViewControllerクラスを確認するとこれを継承していることがわかります。

ではUIViewControllerはどこで定義されたクラスなのかというとUIKitというフレームワークライブラリとも言ったりしますが、そこで定義されています。
ライブラリはある機能を実現するための処理をまとめたものです。
UIKitはUIを構成するためのクラスを提供してくれています。
UILabelUIButtonなど頭に「UI」がついているものは全てUIKitが提供しているクラスです。

ライブラリが提供するクラスや機能を使う場合はファイルの頭でimport ライブラリと宣言してあげる必要があります。
今回はUIKitを使うので頭でimport UIKitとしています。

これで遷移先のクラスは作成できました。
遷移するための処理やその他基本的な処理はUIViewControllerがやってくれるのでSecondViewControllerの中身はとりあえず空で問題ありません。

遷移先のStoryboardを作成する

次はStoryboardを編集します。
SecondViewController.storyboardを開いてください。

作成したばかりなので空の状態です。
まずは土台となるUIViewControllerを配置します。
UIViewControllerもボタンなどの配置と同じです。
[+]をクリックしUIViewControllerを適当な位置に配置してください。
検索から「ViewController」と打てば早く見つけられるかと思います。

スクリーンショット 2020-05-27 1.12.12.png

ViewControllerを選択した状態で[Attribute Inspector]を選択してください。
Inspector内に[Is Initial View Controller]にチェックをいれます。
するとViewControllerの左側に矢印が出ます。

スクリーンショット 2020-05-27 1.15.15.png

ViewControllerは[+]から何個でも配置することができます。
そのため複数配置さえていた場合、このファイルのどのViewControllerを最初に表示すればいいのかInterface Builderがわからなくなります。
[Is Initial View Controller]は「このファイルで最初に表示するViewControllerです」というフラグです。

スクリーンショット 2020-05-27 1.25.25.png

次はViewControllerにSecondViewControllerクラスを設定してあげます。
ViewControllerを選択し、[Identity Inspector]をクリックします。
[Class]という項目があるのでSecondViewControllerを設定します。

ViewControllerの場合[Class]にはUIViewControllerを継承した全てのクラスのうち1つを選択することができます。
ここに設定すると先程作成したSecondViewControllerとStoryboardの中のViewControllerがひも付きます。
【補足】ここに設定するSecondViewControllerはファイル名ではなくクラス名です。

真っ白な画面では遷移したとき少しわかりにくいかもしれないので適当なラベルを配置しておきましょう。
(ラベルの文言はStoryboard上でラベルをダブルクリックすると編集できます)

スクリーンショット 2020-05-27 1.33.20.png

これで遷移先の画面は完成です。

画面遷移する

それでは画面遷移させます。
iOSアプリの画面遷移の方式は何パターンかあります。
今回はその中で最も単純なモーダルという方式を使って画面遷移させます。
モーダルの詳細と他の方式は次回紹介します。

セグエを設定する

画面遷移の実装方法は2通りあります。
ソースコードから直接画面オブジェクトを生成する方法とsegueを使う方法です。
segueもUIKitで提供されている機能の1つで画面と画面を繋ぐオブジェクトです。
矢印のようなものですが実際に見た方が早いです。

今回はこのsegueを使って画面遷移させてみます。

Main.storyboardを開いてください。

まずはStoryboard ReferenceというUIを配置します。
いつも通り[+]ボタンをクリックし、Storyboard Referenceを探します。
これをViewControllerの外側に配置してください。

スクリーンショット 2020-05-27 1.50.37.png

配置するとViewControllerの外側とUIの一覧にStoryboard Referenceが現れます。

スクリーンショット 2020-05-27 1.54.27.png

補足ですが、Storyboard ReferenceはViewControllerの外側に配置されるのでViewControllerの構成には影響しません。
UIの一覧を見ると[View Controller Scene]と同じ階層にあることがわかります。

Storyboard Referenceはその名の通りStoryboardへの参照です。
先程別ファイルとして遷移先としてSecondViewController.storyboardというStoryboardファイルを作成しました。
Main.storyboardSecondViewController.storyboardは全くの別ファイルなのでMain.storyboardには遷移先の情報が必要となります。
その別ファイル情報を設定するためのUIがStoryboard Referenceです。

ではStoryboard ReferenceにSecondViewController.storyboardの情報を設定してあげます。
Storyboard Referenceを選択してください。
選択すると[Attributes Inspector]にStoryboardを設定できる項目があります。
ここにSecondViewController.storyboardを設定してあげましょう。

スクリーンショット 2020-05-27 2.06.39.png

【補足】ここで設定しているのはファイル情報です。そのため[Storyboard]の項目に設定しているのはクラス名ではなくファイル名です。

次はsegueでViewControllerとStoryboard Referenceを繋げてあげます。
ViewControllerの上にあるバーをクリックします。
すると3つのアイコンが表示されるのでその一番左のアイコンをクリックします。
これはViewControllerのオブジェクトを表すアイコンです。
controlキーを押しながらこのアイコンをクリックし、Storyboard Referenceまで青い線を引っ張っていってください。

スクリーンショット 2020-05-27 2.11.15.png

するとStoryboard Referenceの近くに以下のようなポップアップが表示されます。
[Present Modally]を選択します。
これはモーダルで表示するという設定になります。

スクリーンショット 2020-05-27 2.15.17.png

設定するとViewControllerとStoryboard Referenceが矢印で繋がれます。
この矢印がsegueです。

スクリーンショット 2020-05-27 2.19.32.png

segueを選択し、[Attributs Inspector]をクリックしてください。
[Identifier]という項目があるのでsegueのIDを設定します。
このIDはファイル内のsegueの中で一意なものであれば何でも構いません。
ですがわかりやすくするために遷移先の名前を設定するのが一般的です。

スクリーンショット 2020-05-27 2.22.45.png

これでsegueの設定ができ、遷移元のStoryboardの設定は完了です。

画面遷移する

ここまでが画面遷移をするための準備となります。

それでは画面遷移させてみましょう。
ボタンタップのイベントで画面を遷移させたいのでMain.storyboardにボタンを配置し、ViewControllerクラスにタップイベントを紐付けてください。

import UIKit

class ViewController: UIViewController {

    /// 画面遷移ボタンタップ処理
    /// - Parameter sender: ボタン
    @IBAction func didTapTransitionButton(_ sender: Any) {
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

処理自体は非常に簡単でperformSegueというメソッドを使用するだけです。
以下を実装して実行するとSecondViewController画面に遷移します。

@IBAction func didTapTransitionButton(_ sender: Any) {
    self.performSegue(withIdentifier: "SecondViewController", sender: nil)
}

performSegueというメソッドはUIViewControllerで定義されているメソッドで、segueを使って画面遷移するためのメソッドです。
第一引数のwithIdentifierは先程Storyboardでsegueに設定したIDです。
設定したID以外のものを設定するとアプリがクラッシュするので気をつけてください。
第二引数のsenderは画面遷移の際、次の画面に受け渡したいパラメータを設定します。
今回nilを設定していますがこれは何も設定しないという意味です。他の言語ではnullと呼ばれています。

メソッドの先頭にselfというものを付けていますがこれは自分自身のオブジェクトという意味です。
今回でいうとViewController自身です。
実際にはperformSegueUIViewControllerのメソッドですが、クラスを継承した場合継承元クラスのメソッドを自分自身のメソッドとして呼び出すことができます。

これでモーダルという方式の画面遷移をsegueで実現することができました。
モーダルは画面の上に画面が乗るような遷移方式です。

パラメータを受け渡す

performSegueの第二引数senderでパラメータを次の画面に渡せるといいました。
アプリを作っているとどうしても一画面では処理を完結できず、次の画面に情報を渡してあげないと処理できないようなことがあります。
そういった場面ではsenderにパラメータを設定し、次の画面で値を保持してあげます。

実際にやってみましょう。
今回の例では1画面目でテキストをキーボードから入力し、遷移先の画面で入力した文字を表示します。

キーボードから文字を入力するにはUITextFieldを使用します。
Main.storyboardに配置しViewController.swiftにアウトレット接続してください。
(以下の例ではその他に「入力してください」というラベルも配置しています。)

スクリーンショット 2020-05-27 23.30.47.png
スクリーンショット 2020-05-27 23.33.47.png

class ViewController: UIViewController {
    /// テキストフィールド
    @IBOutlet weak var textField: UITextField!

    /// 画面遷移ボタンタップ処理
    /// - Parameter sender: ボタン
    @IBAction func didTapTransitionButton(_ sender: Any) {
        self.performSegue(withIdentifier: "SecondViewController", sender: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

次に遷移先のSecondViewControllerに渡された文字列を表示するためのUILabelを配置してください。
配置したUILabelをSecondViewController.swiftにアウトレット接続します。

スクリーンショット 2020-05-27 23.41.24.png
class SecondViewController: UIViewController {
    /// 入力された文字列を表示するラベル
    @IBOutlet weak var inputtedTextLabel: UILabel!

}

さらにSecondViewController.swiftに入力された文字列を格納しておくinputtedTextというプロパティを宣言しておきます。

class SecondViewController: UIViewController {
    /// 入力された文字列を表示するラベル
    @IBOutlet weak var inputtedTextLabel: UILabel!
    /// 入力された文字列を格納しておくプロパティ
    var inputtedText: String?
}

inputtedTextの型がString?となっていますが?オプショナル型を表します。
オプショナル型はSwift特有の考え方なのですが、値がnilの可能性があるという意味でString?とするとnilになり得るString型という意味になります。
UITextFieldのテキストの初期値はnilでSecondViewControllerに引き渡される文字列がnilになる可能性があるためオプショナル型で宣言しています。
今回はそういうものがあるのかくらいの認識で問題ありません。

さてこれで準備が完了しました。
実際にパラメータを引き渡すコードを書いていきましょう。

パラメータを引き渡すにはまず画面遷移のイベントをフックしてあげる必要があります。
イベントをフックするとは、イベントが発生したときに処理を割り込ませるような仕組みになります。
例えばボタンタップのメソッドもイベントが発生したときに処理を割り込ませているのでフックの一種になるかと思います。

UIViewControllerにはsegueでの画面遷移イベントをフックするメソッドが用意されています。
prepare(for segue: UIStoryboardSegue, sender: Any?)というメソッドです。
これを利用してパラメータを引き渡してあげます。

画面遷移を実行するのは遷移元であるViewControllerの処理なのでViewController.swiftに処理を追加します。

確認のためprepareprint()入れて実行してみましょう。

class ViewController: UIViewController {
    /// テキストフィールド
    @IBOutlet weak var textField: UITextField!

    /// 画面遷移ボタンタップ処理
    /// - Parameter sender: ボタン
    @IBAction func didTapTransitionButton(_ sender: Any) {
        self.performSegue(withIdentifier: "SecondViewController", sender: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    /// 画面遷移イベントをフックする
    /// - Parameters:
    ///   - segue: segue
    ///   - sender: パラメータ
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        print("画面遷移前の処理!")
    }
}

func prepareの前にoverrideとあります。
これは継承元となったクラスに定義されているメソッドを上書きするという意味になります。
UIViewControllerではperformSegueを呼んだ後、segueに紐付けられた画面オブジェクトを作成し、prepareを呼び出すというような処理を行っています。
ここで呼ばれるprepareの処理を上書いてあげることで画面遷移前に好きな処理を記述できるようになります。

prepareの引数について。
第一引数はsegueには画面遷移に使用したsegueが渡されてきます。
今回の場合だとSecondViewControllerへのsegueです。
segueの中には遷移先の情報があり、遷移先の画面オブジェクトも含まれます。
このsegueから取り出した画面オブジェクトに対し好きな処理をすることができます。

第二引数のsenderにはperformSegueの第二引数に設定した値が入ります。

それでは実際にパラメータを引き渡す処理を実装します。
以下のように実装してください。

class ViewController: UIViewController {
    /// テキストフィールド
    @IBOutlet weak var textField: UITextField!

    /// 画面遷移ボタンタップ処理
    /// - Parameter sender: ボタン
    @IBAction func didTapTransitionButton(_ sender: Any) {
        // textFieldから入力されているテキストを取得する
        let text = textField.text
        // 画面遷移のパラメータとしてtextを設定する
        self.performSegue(withIdentifier: "SecondViewController", sender: text)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    /// 画面遷移イベントをフックする
    /// - Parameters:
    ///   - segue: segue
    ///   - sender: パラメータ
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // segueからSecondViewControllerを取得する
        if let secondViewController = segue.destination as? SecondViewController {
            // senderをStringにキャストする
            let paramater = sender as? String
            // SecondViewControllerのinputtedTextにparamaterを設定する
            secondViewController.inputtedText = paramater
        }
    }
}

まずはdidTapTransitionButtonでの処理から。
UITextFieldtextプロパティにはユーザがキーボードから入力した文字列が入っています。
UILabelと似たような感じですね。
ここで取得した値をperformSegueの第二引数に画面遷移のパラメータとして引き渡しています。

prepareでは実際に遷移先にパラメータを設定しています。
UIStoryboardSeguedestinationには遷移先の画面オブジェクトが設定されています。
asキャストと呼ばれる処理で型を変換しています。
定義を見るとわかりますがdestinationUIViewController型です。
今回はSecondViewControllerinputtedTextにパラメータを設定してあげたいのですが、UIViewControllerにはinputtedTextは定義されていません。
そのため一度キャストで型変換してあげる必要があります。

if let ~~はSwift特有の書き方なので詳細については別の機会に説明します。
簡単にいうとdestinationSecondViewControllerならsecondViewControllerという変数を宣言するというような処理です。

let paramater = sender as? String
これもキャストしています。
senderAny型ですがinputtedTextString型なので型が合いません。
そのため一度キャストした値をparamaterに格納しています。

secondViewController.inputtedText = paramaterはそのままで、inputtedTextparamaterをセットしています。

これでSecondViewControllerにパラメータを引き渡すことができました。
パラメータを引き渡した後はSecondViewControllerは自由にinputtedTextを使うことができます。

この後はSecondViewControllerviewDidLoadなどでUILabelの表示をinputtedTextで更新してあげると表示が変更されます。
以下のように実装してから実行すると入力したテキストの値が遷移先に表示されます。

class SecondViewController: UIViewController {
    /// 入力された文字列を表示するラベル
    @IBOutlet weak var inputtedTextLabel: UILabel!
    /// 入力された文字列を格納しておくプロパティ
    var inputtedText: String?

    /// 画面読み込み完了後処理
    override func viewDidLoad() {
        super.viewDidLoad()

        // inputtedTextLabelの表示をinputtedTextの値にする
        self.inputtedTextLabel.text = self.inputtedText
    }
}

もしキーボードで画面遷移ボタンが押せない場合はViewController.swiftに以下の処理を追加してください。
画面のどこかをタップするとキーボードを閉じるという処理です。

/// 画面タップでテキストフィールドを閉じる
/// - Parameters:
///   - touches: touches
///   - event: event
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.view.endEditing(true)
}

最後に

今回は画面遷移の方法とパラメータの引き渡し方について説明しました。
だんだんとSwiftプログラミングの要素が入ってきたので難しくなってきたかと思います。
ですが画面遷移はアプリで必ずといっていいほど入っている処理なので習得してください。

今回モーダル遷移を取り扱ったので次回は別の方式について説明します。

コメント

タイトルとURLをコピーしました