はじめに
こんにちは。
UINavigationControllerについて
少しだけ気になったので、メモとしてまとめて投稿してみました。作成時(Xcode8.2.1)(Swift3.0.2)
至らぬ点など多々あると思いますが、コメントなど頂けたら幸いです。
サンプル
今回は
NavigationController × 1
UIViewController × 2
を用いてshowやpopと遷移をして繋がりのある画面遷移を実現します。
このようにsegueで繋げて1つのStoryboardで管理するのも良いですが、
今回はこれを分割して管理してみたいと思います。
コードとStoryboardで分割する
Storyboardの準備
1つのUIViewControllerにつき1つのStoryboardを用意します。
今回はピンク色のUIViewController(以下ピンク色と略)をルートに設定したいので、StoryboardにてUIViewControllerを選択し、
Editor -> Embed In -> Navigation Controller
でNavigationControllerがピンク色と繋がります。
※ここではUIViewとUIButtonを設置しました。
繋げると、ピンク色にNavigationBarが表示されます。
UIViewの上部はTopLayoutGuide.Bottomへ0の制約を与え、NavigationBarにぴったり付いています。
次に遷移先のUIViewControllerを用意します。
今回は青色のUIViewController(以下青色と略)にしました。
こちらもStoryboardを新規作成し、UIViewControllerを設置します。
※ここでもUIViewとUIButtonを設置しました。
Simulated MetricsでTop BarをTranslucent Navigation Barに設定するとNavigationBarがある状態が確認できるので、見やすくなると思います。
(Top Barを設定しなくても、NavigationControllerを持つViewControllerからshowで遷移をすれば実行時にはNavigationBarが表示されます。乗っているUIViewなどにTopLayoutGuide.Bottomへの制約がある場合、UIViewはNavigationBarからの距離になります)
TopBarの種類 | 詳細 |
---|---|
Translucent Navigation Bar | 半透明のNavigationBar,高さは約64 |
Translucent Navigation Bar With Prompt | Promptの分スペースが空いた半透明のNavigationBar,高さは約94 |
Translucent Black Navigation Bar | 黒色テーマで半透明のNavigationBar,高さは約64 |
Translucent Black Navigation Bar With Prompt | Promptの分スペースが空いた黒色テーマで半透明のNavigationBar,高さは約94 |
Opaque Navigation Bar | 不透明のNavigationBar,高さは約64 |
Opaque Navigation Bar With Prompt | Promptの分スペースが空いた不透明のNavigationBar,高さは約94 |
Opaque Black Navigation Bar | 黒色テーマで不透明のNavigationBar,高さは約64 |
Translucent Black Navigation Bar With Prompt | Promptの分スペースが空いた黒色テーマで不透明のNavigationBar,高さは約94 |
ここでの設定はあくまでStoryboard上の見た目なので、実際の設定はStoryboard上でNavigationControllerの持つNavigationBarを設定したり、コードで設定する必要があります。
Swiftファイルの準備
画面遷移のコードは以下のようになっています。
遷移 | コード |
---|---|
show(次へ) | navigationController?.show(_:sender:) |
pop(戻る) | navigationController?.popViewController(animated:) |
ピンク色のViewController
import UIKit
class PinkViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func nextAction(_ sender: Any) {
//Stroyboard生成
let storyboard = UIStoryboard(name: "Blue", bundle: nil)
//IB上でInitialの矢印をつけたVCを生成
let blueVC = storyboard.instantiateInitialViewController()!
navigationController?.show(blueVC, sender: nil)
}
}
青色のViewController
import UIKit
class BlueViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func backAction(_ sender: Any) {
//前のViewControllerを取得
if let pinkVC = navigationController?.viewControllers[0] as? PinkViewController {
//なんらかの処理
}
_ = navigationController?.popViewController(animated: true)
}
}
Storyboard Referenceで分割する
Storyboardの準備
ピンク色のあるStoryboardにStoryboard Referenceを置き、
Segueとして結びます。遷移先のViewControllerを利用できるようにSegueにIDもつけます。
Swiftファイルの準備
画面遷移のコードは以下のようになっています。
ピンク色のViewController
import UIKit
class PinkViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//セグエのIDから判別
if (segue.identifier == "toBlue") {
guard let blueVC = segue.destination as? BlueViewController else {
return
}
//なんらかの処理
}
}
}
青色のViewController
import UIKit
class BlueViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func backAction(_ sender: Any) {
//前のViewControllerを取得
if let pinkVC = navigationController?.viewControllers[0] as? PinkViewController {
//なんらかの処理
}
_ = navigationController?.popViewController(animated: true)
}
}
NavigationBarの設定
NavigationBarをStoryboard上で設定する場合
UINavigationControllerはNavigationBarを持っていることをStoryboard上で確認できます。
設定をするとpopやshowと繋がるUIViewController全てに反映されます。
(1つ1つに設定をする場合はコードで行う必要があります。)
NavigationBarをコードで設定する場合
上でも記させて頂きましたが、NavigationControllerを持つViewControllerから遷移をすれば実行時にはNavigationBarが表示されます。よってそれぞれのViewController内で以下のコードを記述することで設定することができます。(以下は設定例)
Style(黒色テーマなどのテーマ設定)
navigationController?.navigationBar.barStyle = .default
Translucent(半透明であるかどうかの設定)
navigationController?.navigationBar.isTranslucent = true
Bar Tint(NavigationBarの色の設定)
navigationController?.navigationBar.barTintColor = UIColor.clear
Shadow(背景画像と一緒に設定する必要があり、NavigationBarの影の設定)
navigationController?.navigationBar.setBackgroundImage(UIImage(named: "名前"), for: .default)
Back(Back Maskと一緒に設定する必要があり、戻るボタンの設定)
navigationController?.navigationBar.backIndicatorImage = UIImage(named: "名前")
Back Mask
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "名前")
Title Font,Color,Shadow(タイトル文字列の設定)
let shadow = NSShadow()
shadow.shadowOffset = CGSize(width: 2, height: 2)
shadow.shadowColor = UIColor.green
shadow.shadowBlurRadius = 5
navigationController?.navigationBar.titleTextAttributes = [
//フォント
NSFontAttributeName:UIFont.systemFont(ofSize: 18),
//文字色
NSForegroundColorAttributeName: UIColor.red,
//影
NSShadowAttributeName: shadow
]
NavigationItemの設定
NavigationItemをStoryboard上で設定する場合
NavigationControllerと繋がっているルートとなるViewControllerはNavigationItemを持っていることをStoryboard上で確認できます。
ルート以外のViewControllerにはStoryboard上で明示的にNavigationItemを入れてあげる必要があります。
NavigationItemをコードで設定する場合
それぞれのViewController内で以下のコードを記述することで設定することができます。(以下は設定例)
Title(タイトルとなる文字列の設定)
navigationItem.title = "タイトル"
Prompt(タイトルの上に表示される文字列の設定)
navigationItem.prompt = "プロンプト"
Back Button(戻るボタンの文字列)
ルートのViewController
let backButtonItem = UIBarButtonItem(title: "戻る", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButtonItem
それ以外のViewController
navigationItem.backBarButtonItem?.title = "戻る"
次の画面で表示される戻るボタンの文字列の設定になります。
(ピンク色で設定すると青色で表示される)
デフォルトの戻るボタンについて
現状、青色のViewControllerには<< BackというUIButtonを付けているので、
戻るボタンが押された時の処理を記述できるのですが、UINavigationControllerからデフォルトで作成される戻るボタンのアクションを取ることが難しく、
もしも戻るボタンが押された時に行いたい処理がある場合は
didMoveで親コンテナが存在するかどうかでの方法
戻るボタンが押されてすぐの検知はできないのですが、親へと遷移完了したことの検知ができます。
以下はコード例です。//戻るボタンを押した瞬間ではないが、押されて遷移された時の処理 override func didMove(toParentViewController parent: UIViewController?) { super.willMove(toParentViewController: parent) if parent == nil { print("1つ前のViewControllerに遷移完了") } }
NavigationBarを作成する方法
- デフォルトで用意される矢印が利用できないこと
- StoryboardでルートのViewControllerは消すことのできないNavigation Itemを持つこと。
が気になりますが、NavigationControllerをStoryboardで繋げるとNavigationBarが自動的に表示されるのでNavigationControllerを選択し、Bar VisibilotyをOFFにすると良いかと思います。
以上のような方法があるみたいです。
参考にさせていただいた記事
戻るボタンのイベントについて
UINavigationControllerについて
見て頂いてありがとうございます。