はじめに
前回は条件分岐など少しプログラミング的な処理を入れてUIを更新しする方法ついて投稿しました。
SwiftとUIの接続編3:https://qiita.com/euJcIKfcqwnzDui/items/93f010b989a4d333f0b9
基本的なアプリには画面がいくつかあります。
今回は画面を追加し、アプリを作る上で必須となる「画面遷移」について説明します。
少しプログラミングの話も出てくるかと思うので一度こちらの記事に目を通しておくといいかもしれません。
それではプロジェクトを開きます。
前回までで処理やUIが少し増えたので今回は新しいプロジェクトを作って進めます。
もちろん前回までのプロジェクトを使って頂いても構いません。
画面を追加する
遷移先画面用のファイルを追加する
まず画面遷移するためには遷移先の画面が必要です。
画面を作るためにはSwiftファイルとStoryboardのファイルが必要になります。
遷移先の画面はSecondViewController
という名前にしてファイルを作っていきましょう。
まずXcodeから追加先のフォルダを右クリックします。
メニューが表示されるので[New File...]を選択します。
まずSwiftファイルを作ります。
表示されたポップアップから[Swift File]を選択し[Next]をクリックします。
[Save As:]に作りたいファイル名を拡張子なしで入力し[Create]をクリックします。
SecondViewController.swift
が作成されました。
同じ手順でStoryboardファイルも作成します。
SecondViewController.storyboard
が作成されました。
画面クラスを作成する
画面を表示するためにはまず画面用のクラスが必要です。
クラス名をSecondViewController
として以下のようにSecondViewController.swift
に作成します。
ちなみにファイル名とその中に定義するクラス名は必ずしも一致している必要はありません。
ですがファイルを見ればどのクラスが書かれたファイルなのかすぐわかるように一致させることをおすすめします。
import UIKit
class SecondViewController: UIViewController {
}
これで画面のクラスは作成できました。
このコードについて簡単に説明します。
まずclass SecondViewController
は定義するクラス名を表します。
このあたりは別記事の説明を参照してください。
クラス名に:
を付けてUIViewController
と書かれています。
これは継承といい、オブジェクト指向の考え方の1つです。
継承とはあるクラスをベースとして新しいクラスを作成する方法です。
継承元の特性を引き継がせるようなイメージです。拡張しているといってもいいかもしれません。
この段階ではSecondViewController
にはプロパティもメソッドも持っていないのでUIViewController
とほぼ同じ特性を持つクラスです。
UIViewController
は全ての画面のベースとなるクラスです。
表示する画面となるViewや画面遷移のメソッドなどを持っています。
プロジェクト作成時に自動生成されたViewController
クラスを確認するとこれを継承していることがわかります。
ではUIViewController
はどこで定義されたクラスなのかというとUIKit
というフレームワーク、ライブラリとも言ったりしますが、そこで定義されています。
ライブラリはある機能を実現するための処理をまとめたものです。
UIKit
はUIを構成するためのクラスを提供してくれています。
UILabel
やUIButton
など頭に「UI」がついているものは全てUIKitが提供しているクラスです。
ライブラリが提供するクラスや機能を使う場合はファイルの頭でimport ライブラリ
と宣言してあげる必要があります。
今回はUIKit
を使うので頭でimport UIKit
としています。
これで遷移先のクラスは作成できました。
遷移するための処理やその他基本的な処理はUIViewController
がやってくれるのでSecondViewController
の中身はとりあえず空で問題ありません。
遷移先のStoryboardを作成する
次はStoryboardを編集します。
SecondViewController.storyboard
を開いてください。
作成したばかりなので空の状態です。
まずは土台となるUIViewController
を配置します。
UIViewController
もボタンなどの配置と同じです。
[+]をクリックしUIViewController
を適当な位置に配置してください。
検索から「ViewController」と打てば早く見つけられるかと思います。
ViewControllerを選択した状態で[Attribute Inspector]を選択してください。
Inspector内に[Is Initial View Controller]にチェックをいれます。
するとViewControllerの左側に矢印が出ます。
ViewControllerは[+]から何個でも配置することができます。
そのため複数配置さえていた場合、このファイルのどのViewControllerを最初に表示すればいいのかInterface Builderがわからなくなります。
[Is Initial View Controller]は「このファイルで最初に表示するViewControllerです」というフラグです。
次はViewControllerにSecondViewController
クラスを設定してあげます。
ViewControllerを選択し、[Identity Inspector]をクリックします。
[Class]という項目があるのでSecondViewController
を設定します。
ViewControllerの場合[Class]にはUIViewController
を継承した全てのクラスのうち1つを選択することができます。
ここに設定すると先程作成したSecondViewController
とStoryboardの中のViewControllerがひも付きます。
【補足】ここに設定するSecondViewController
はファイル名ではなくクラス名です。
真っ白な画面では遷移したとき少しわかりにくいかもしれないので適当なラベルを配置しておきましょう。
(ラベルの文言はStoryboard上でラベルをダブルクリックすると編集できます)
これで遷移先の画面は完成です。
画面遷移する
それでは画面遷移させます。
iOSアプリの画面遷移の方式は何パターンかあります。
今回はその中で最も単純なモーダルという方式を使って画面遷移させます。
モーダルの詳細と他の方式は次回紹介します。
セグエを設定する
画面遷移の実装方法は2通りあります。
ソースコードから直接画面オブジェクトを生成する方法とsegueを使う方法です。
segueもUIKit
で提供されている機能の1つで画面と画面を繋ぐオブジェクトです。
矢印のようなものですが実際に見た方が早いです。
今回はこのsegueを使って画面遷移させてみます。
Main.storyboard
を開いてください。
まずはStoryboard ReferenceというUIを配置します。
いつも通り[+]ボタンをクリックし、Storyboard Referenceを探します。
これをViewControllerの外側に配置してください。
配置するとViewControllerの外側とUIの一覧にStoryboard Referenceが現れます。
補足ですが、Storyboard ReferenceはViewControllerの外側に配置されるのでViewControllerの構成には影響しません。
UIの一覧を見ると[View Controller Scene]と同じ階層にあることがわかります。
Storyboard Referenceはその名の通りStoryboardへの参照です。
先程別ファイルとして遷移先としてSecondViewController.storyboard
というStoryboardファイルを作成しました。
Main.storyboard
とSecondViewController.storyboard
は全くの別ファイルなのでMain.storyboard
には遷移先の情報が必要となります。
その別ファイル情報を設定するためのUIがStoryboard Referenceです。
ではStoryboard ReferenceにSecondViewController.storyboard
の情報を設定してあげます。
Storyboard Referenceを選択してください。
選択すると[Attributes Inspector]にStoryboardを設定できる項目があります。
ここにSecondViewController.storyboard
を設定してあげましょう。
【補足】ここで設定しているのはファイル情報です。そのため[Storyboard]の項目に設定しているのはクラス名ではなくファイル名です。
次はsegueでViewControllerとStoryboard Referenceを繋げてあげます。
ViewControllerの上にあるバーをクリックします。
すると3つのアイコンが表示されるのでその一番左のアイコンをクリックします。
これはViewControllerのオブジェクトを表すアイコンです。
controlキーを押しながらこのアイコンをクリックし、Storyboard Referenceまで青い線を引っ張っていってください。
するとStoryboard Referenceの近くに以下のようなポップアップが表示されます。
[Present Modally]を選択します。
これはモーダルで表示するという設定になります。
設定するとViewControllerとStoryboard Referenceが矢印で繋がれます。
この矢印がsegueです。
segueを選択し、[Attributs Inspector]をクリックしてください。
[Identifier]という項目があるのでsegueのIDを設定します。
このIDはファイル内のsegueの中で一意なものであれば何でも構いません。
ですがわかりやすくするために遷移先の名前を設定するのが一般的です。
これで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
自身です。
実際にはperformSegue
はUIViewController
のメソッドですが、クラスを継承した場合継承元クラスのメソッドを自分自身のメソッドとして呼び出すことができます。
これでモーダル
という方式の画面遷移をsegueで実現することができました。
モーダルは画面の上に画面が乗るような遷移方式です。
パラメータを受け渡す
performSegue
の第二引数sender
でパラメータを次の画面に渡せるといいました。
アプリを作っているとどうしても一画面では処理を完結できず、次の画面に情報を渡してあげないと処理できないようなことがあります。
そういった場面ではsender
にパラメータを設定し、次の画面で値を保持してあげます。
実際にやってみましょう。
今回の例では1画面目でテキストをキーボードから入力し、遷移先の画面で入力した文字を表示します。
キーボードから文字を入力するにはUITextFieldを使用します。
Main.storyboard
に配置しViewController.swift
にアウトレット接続してください。
(以下の例ではその他に「入力してください」というラベルも配置しています。)
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
にアウトレット接続します。
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
に処理を追加します。
確認のためprepare
にprint()
入れて実行してみましょう。
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
での処理から。
UITextField
のtext
プロパティにはユーザがキーボードから入力した文字列が入っています。
UILabel
と似たような感じですね。
ここで取得した値をperformSegue
の第二引数に画面遷移のパラメータとして引き渡しています。
prepare
では実際に遷移先にパラメータを設定しています。
UIStoryboardSegue
のdestination
には遷移先の画面オブジェクトが設定されています。
as
はキャストと呼ばれる処理で型を変換しています。
定義を見るとわかりますがdestination
はUIViewController
型です。
今回はSecondViewController
のinputtedText
にパラメータを設定してあげたいのですが、UIViewController
にはinputtedText
は定義されていません。
そのため一度キャストで型変換してあげる必要があります。
if let ~~
はSwift特有の書き方なので詳細については別の機会に説明します。
簡単にいうとdestination
がSecondViewController
ならsecondViewController
という変数を宣言するというような処理です。
let paramater = sender as? String
これもキャストしています。
sender
はAny
型ですがinputtedText
はString
型なので型が合いません。
そのため一度キャストした値をparamater
に格納しています。
secondViewController.inputtedText = paramater
はそのままで、inputtedText
にparamater
をセットしています。
これでSecondViewController
にパラメータを引き渡すことができました。
パラメータを引き渡した後はSecondViewController
は自由にinputtedText
を使うことができます。
この後はSecondViewController
のviewDidLoad
などで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プログラミングの要素が入ってきたので難しくなってきたかと思います。
ですが画面遷移はアプリで必ずといっていいほど入っている処理なので習得してください。
今回モーダル遷移を取り扱ったので次回は別の方式について説明します。
画面遷移編2:https://qiita.com/euJcIKfcqwnzDui/items/6d37aaf00c0bc7ce26ca
本連載ではプログラミング未経験からiOSアプリ開発が行えるようになることを目的としています。
今までの投稿をまとめていますのでこちらもご覧ください。
http://naoyalog.com/