59
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ナビゲーションバーのカスタマイズ一覧(iOS)

Last updated at Posted at 2021-03-21

はじめに

ナビゲーションバーをカスタマイズする方法を毎回忘れて実装に時間がかかるため、まとめました。

環境

  • OS:macOS Big Sur 11.1
  • Xcode:12.4 (12D4e)
  • Swift:5.3.2
  • iOS:14.4

ナビゲーションバーのカスタマイズ一覧

ナビゲーションバーのタイトルに画像をセットする

UINavigationItem.titleView に画像をセットすることで、ナビゲーションバーのタイトルを画像にできます。

MonsterIndexListViewController.swift
final class MonsterIndexListViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let imageView = UIImageView(image: UIImage(named: "navi_zukan"))
        imageView.contentMode = .scaleAspectFit
        self.navigationItem.titleView = imageView
    }

}
テキスト 画像
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 20.32.26.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 20.30.14.png

UIImageView.contentMode.scaleAspectFit にすると、画像の縦横比を変えずに表示できます。

ナビゲーションバーの戻るボタンの画像を変更する

UINavigationBarbackIndicatorImagebackIndicatorTransitionMaskImage を変更することで、戻るボタンの画像を変更できます。

MonsterIndexListViewController.swift
final class MonsterIndexListViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        let image = UIImage(named: "index_icon_back")
        self.navigationController?.navigationBar.backIndicatorImage = image
        self.navigationController?.navigationBar.backIndicatorTransitionMaskImage = image
    }

}
画像未変更 画像変更
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.09.43.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.34.20.png

セットした画像は以下であり、 tintColor が反映されてしまいます。
icon_back.png

tintColor を反映させない方法がわからなかったので、ご存じの方がいたら教えていただけると嬉しいです。

2021/03/23, 追記
コメント で教えていただきました。

対象画像のRender Asを Default から Original Image に変えると tintColor が反映されなくなります。
スクリーンショット_2021-03-23_19_40_17_after.png
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-23 at 19.39.01.png

ただ画像の位置が上に寄るのは直りません。
画像のサイズを調整すればかんたんに対応できます。
参考: https://sarunw.com/posts/how-to-change-back-button-image/#position

UIImage の位置を変える方法もありますが、 tintColor が反映されるのと、 UIImageView の位置は変わらないので見切れることがあるため、ベターな方法ではなさそうです。
参考: https://stackoverflow.com/questions/29445644/vertically-center-backindicatorimage-in-swift

ナビゲーションバーの戻るボタンのテキストを非表示にする

iOS 14以上の場合、 遷移元のビューコントローラー
UINavigationItem.backButtonDisplayMode.minimal にすることで、戻るボタンのテキストを非表示にできます。

MainViewController.swift
final class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.navigationItem.backButtonDisplayMode = .minimal
    }

}
表示 非表示
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.09.03.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.09.43.png

戻るボタンの長押し時にビューコントローラーの title が表示されるので、戻るボタンを非表示にする場合でもセットするのが望ましいです。

MainViewController.swift
final class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
+       self.title = "メイン"
        self.navigationItem.backButtonDisplayMode = .minimal
    }

}
タイトル未セット タイトルセット
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.17.05.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 19.11.50.png

戻るボタンのタイトルに半角スペースをセットする方法もよく見ますが、iOS 14以降では戻るボタン長押し時のメニューにタイトルが表示されなくなるので望ましくありません。

ナビゲーションバーの戻るボタンの色を変更する

UINavigationBartintColor を変更することで、戻るボタンの色を変更できます。

MonsterIndexListViewController.swift
final class MonsterIndexListViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.tintColor = UIColor(named: "tekimon_khaki")
    }

}
色未変更 色変更
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-23 at 20.18.10.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-23 at 20.21.45.png

一部のビューコントローラーのみナビゲーションバーの戻るボタンの色を変更する場合、戻し忘れに気をつけてください。

戻すには nil をセットします。

MainController.swift
final class MainViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.tintColor = nil
    }

}

ナビゲーションバーの背景色を変更する

UINavigationBarbarTintColor を変更することで、ナビゲーションバーの背景色を変更できます。

MonsterIndexListViewController.swift
final class MonsterIndexListViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.barTintColor = UIColor(named: "tekimon_khaki")
    }

}
背景色未変更 背景色変更
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-23 at 21.01.22.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-23 at 20.59.02.png

一部のビューコントローラーのみナビゲーションバーの背景色を変更する場合、戻し忘れに気をつけてください。

戻すには nil をセットします。

MainController.swift
final class MainViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.barTintColor = nil
    }

}

ナビゲーションバーを透過する

UINavigationBarbackgroundImageshadowImage を初期化することで、ナビゲーションバーを透過できます。

MonsterIndexListViewController.swift
final class MonsterIndexListViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
        self.navigationController?.navigationBar.shadowImage = UIImage()
    }

}
非透過 透過
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 20.39.05.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 20.36.22.png

一部のビューコントローラーのみナビゲーションバーを透過する場合、戻し忘れに気をつけてください。

非透過にするには nil をセットします。

MainViewController.swift
final class MainViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
        self.navigationController?.navigationBar.shadowImage = nil
    }

}

私が参考にしたサイトでは、 UINavigationBar に以下のような拡張メソッドを実装していました。
意図が明確になっていいと思います。

UINavigationBar+Transparency.swift
extension UINavigationBar {

    func enableTransparency() {
        setBackgroundImage(UIImage(), for: .default)
        self.shadowImage = UIImage()
    }

    func disableTransparency() {
        setBackgroundImage(nil, for: .default)
        self.shadowImage = nil
    }

}

ナビゲーションバーを非表示にする

UINavigationController.setNavigationBarHidden(_:animated:) メソッドを呼び出すことで、ナビゲーションバーの表示/非表示を切り替えられます。

MainViewController.swift
final class MainViewController: UIViewController {

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.setNavigationBarHidden(true, animated: false)
    }

}
表示 非表示
Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 18.38.41.png Simulator Screen Shot - iPhone SE (2nd generation) - 2021-03-21 at 18.35.47.png

ナビゲーションバーの表示/非表示が混在しているアプリの場合、画面を遷移するたびにナビゲーションバーの表示も切り替える必要があるので、 viewWillAppear(_:) メソッド内で実行すべきです。

ナビゲーションバーを表示 or 隠し忘れないように気をつけてください。

おまけ: スクリーンショットのアプリ

スクリーンショットに使ったアプリは、先日行われたHack Day 2021で私たちのチームが開発しました!

詳細は他のメンバーが書いてくれたので、ぜひ見てください。

メンバー URL
@hcrane14 https://note.com/hcrane/n/n98a8f1157390
@totokit4 https://note.com/totokit4/n/ne82547d53e05

おわりに

これでナビゲーションバーをカスタマイズする案件が来ても安心です :relaxed:

self.navigationController を変更すると他のビューコントローラーにも影響するので viewWillAppear(_:) で行って戻すのを忘れない、 self.navigationItem は変更しても他のビューコントローラーに影響しないので viewDidLoad() で行う、と覚えておくといいです(間違っていたらすみません)。

参考リンク

59
43
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
59
43

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?