【Swift】Navigation Barの使い方。タイトルを画像にしたり、高さや行数を変更する方法。(Swift 2.1、XCode 7.2)
2020年6月16日
ナビゲーションバーのタイトルをカスタマイズする
本記事では、Navigation Item(以下、ナビゲーションアイテム)に設定するタイトルをカスタマイズする方法を説明する。
タイトルを画像にする
まずはタイトルを画像に変更してみよう。作業開始前のXcodeプロジェクトをGitHubに置いたので、手順を試してみる人はご利用されたし。
⇒「テスト用プロジェクト」
ViewController.swiftを以下のコードに変更する。
ナビゲーションアイテムはtitleプロパティの他にtitleViewというプロパティも持っていて、titleViewプロパティに値を設定するとそれが優先されてタイトルに表示される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// // ViewController.swift // import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //ナビゲーションアイテムのタイトルに画像を設定する。 self.navigationItem.titleView = UIImageView(image:UIImage(named:"title_img.png")) } } |
ストーリーボードを開き、下図赤枠のView Controllerを選択する。黄緑枠のアイデンティティインスペクタボタンを押して設定画面を開き、Classに「ViewController」を設定する。
これで昼、夕方の両方の画面にViewControllerクラスが使われるようになった。
以下は実際のプレイ動画。タイトルに画像が表示されるようになった。
カスタムクラスでタイトルを画像にする
先ほどの実装の欠点は、新しいビューコントローラーを作る度にタイトルに画像を設定するコードを書かなければならない点である。単純なコードなので苦労はしないが、冗長なコードを増やさないためにもナビゲーションアイテムのタイトルを設定する箇所は1つにしておきたい。
そこでNavigation Controller(以下、ナビゲーションコントローラー)のサブクラスを作り、画面遷移時のデリゲートメソッドでタイトルに画像を設定する。なお、先ほどのViewController.swiftの変更は元に戻しておくこと。
メニューから「File」⇒「New」⇒「File…」を選択する。
テンプレートを選択する画面が表示されるので、「iOSのSource」⇒「Cocoa Touch Class」を選択する。
クラス名を入力する画面が表示されるので、Classに「TestNavigationController」、Subclass ofに「UINavigationController」を入力し、Nextボタンを押す。
保存先を指定する画面が表示されるので、プロジェクトと同じ場所であることを確認し、Createボタンを押す。
TestNavigationController.swiftを以下のコードに変更する。
「画面遷移後の呼び出しメソッド」でナビゲーションバーにスタックされているナビゲーションアイテムの中の一番上のアイテムのtitleViewプロパティに画像を設定している。
ナビゲーションアイテムはナビゲーションバーの中に配列で保持されていて、push、popで出し入れされながら画面遷移時に利用されるので、一番上のアイテムが画面遷移後のナビゲーションアイテムになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// // TestNavigationController.swift // import UIKit class TestNavigationController: UINavigationController, UINavigationControllerDelegate { //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //デリゲート先に自分を設定する。 self.delegate = self } //画面遷移後の呼び出しメソッド func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) { //ナビゲーションアイテムのタイトルに画像を設定する。 self.navigationBar.topItem!.titleView = UIImageView(image:UIImage(named: "title_img.png")) } } |
以下は実際のプレイ動画。画面遷移が終わってから画像が現れるのが気になるところではある。
ナビゲーションバーの高さを調整する
ナビゲーションバーの高さは画像の大きさに合わせて自動で伸縮することはないので、以下の画像のように、大きい画像をタイトルに設定すると画像がナビゲーションバーをはみ出してしまう。
そこで、ナビゲーションバーの高さを変更しよう。
TestNavigationController.swiftを以下のコードに変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// // TestNavigationController.swift // import UIKit class TestNavigationController: UINavigationController, UINavigationControllerDelegate { //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //デリゲート先に自分を設定する。 self.delegate = self } //画面遷移後の呼び出しメソッド func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) { //ナビゲーションアイテムのタイトルに画像を設定する。 self.navigationBar.topItem!.titleView = UIImageView(image:UIImage(named: "title_img.png")) //ナビゲーションバーの高さを設定する。 self.navigationBar.frame = CGRectMake(0,0, UIScreen.mainScreen().bounds.size.width, 80) } } |
以下は実際のプレイ動画。ナビゲーションバーの高さが広くなった。
しかし、「画面遷移後の呼び出しメソッド」は別の画面に移動したときに実行されるため、画面端末の向きを縦横に切り替えると高さが元に戻ってしまう。
ナビゲーションバーの体裁を変更するにはナビゲーションバーのサブクラスを使う必要があるようだ。⇒「stackoverflowの投稿」
そこでナビゲーションバーのサブクラスを作ってバーの高さを調整してみよう。メニューから「File」⇒「New」⇒「File…」を選択する。
テンプレートを選択する画面が表示されるので、「iOSのSource」⇒「Cocoa Touch Class」を選択する。
クラス名を入力する画面が表示されるので、Classに「TestNavigationBar」、Subclass ofに「UINavigationBar」を入力し、Nextボタンを押す。
保存先を指定する画面が表示されるので、プロジェクトと同じ場所であることを確認し、Createボタンを押す。
TestNavigationBar.swiftを以下のコードに変更する。ビューの表示が更新されるときに「ビューのサイズを返すメソッド」と「サブビューのレイアウトを行うメソッド」が呼び出される。
「ビューのサイズを返すメソッド」では、ビューの高さを80に変更してサイズを返している。「サブビューのレイアウトを行うメソッド」では、サブビューがUIImageViewクラスだった場合にY座標を15に変更している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// // TestNavigationBar.swift // import UIKit class TestNavigationBar: UINavigationBar { //ビューのサイズを返すメソッド override func sizeThatFits(size: CGSize) -> CGSize { let oldSize:CGSize = super.sizeThatFits(size) let newSize:CGSize = CGSizeMake(oldSize.width, 80) return newSize } //サブビューのレイアウトを行うメソッッド override func layoutSubviews() { super.layoutSubviews() //ビューに含まれるサブビューを1つずつ取得する。 for view: UIView in self.subviews { if(NSStringFromClass(view.dynamicType) == "UIImageView") { //サブビューのクラスがUIImageViewの場合、Y座標を15にする。 view.frame.origin.y = 15 } } } } |
ストーリーボードを開き、下図赤枠の「Navigation Bar」を選択する。黄緑枠のアイデンティティインスペクタボタンを押して設定画面を表示し、Classに「TestNavigationBar」を設定する。これでナビゲーションバーの表示にカスタムクラスが使われるようになった。
以下は実際のプレイ動画。端末の向きを変更してもナビゲーションバーの高さが80で保たれるようになった。
タイトルを2行で表示する
titleViewには画像に限らずUIViewクラスを継承している部品なら何でも設定できる。例えば、TextNavigationController.swiftを以下のコードに変更すると、タイトルとサブタイトルの2行が表示される。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// // TestNavigationController.swift // import UIKit class TestNavigationController: UINavigationController, UINavigationControllerDelegate { //最初からあるメソッド override func viewDidLoad() { super.viewDidLoad() //デリゲート先に自分を設定する。 self.delegate = self } //画面出現後の呼び出しメソッド func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) { //スタックビューを作成 let stackView = UIStackView() stackView.axis = .Vertical stackView.alignment = .Center stackView.frame = CGRectMake(0,0,100,40) //タイトルのラベルを作成する。 let testLabel1 = UILabel(frame:CGRectMake(0,0,100,20)) testLabel1.text = "タイトル" //サブタイトルを作成する。 let testLabel2 = UILabel(frame:CGRectMake(0,0,100,20)) testLabel2.text = "サブタイトル" //スタックビューに追加する。 stackView.addArrangedSubview(testLabel1) stackView.addArrangedSubview(testLabel2) //ナビゲーションバーのタイトルに設定する。 self.navigationBar.topItem!.titleView = stackView } } |