UINavigationControllerに関するちょっとした躓き

インターン先でやってる開発の中で、
UINavigationControllerに関してちょっと立ち止まったところがあったので
メモしておきます。

躓きポイント

ページングビューを簡単に実装できるParchmentというライブラリを使ったPagingViewControllerをNavigationControllerの元に配置しようとしたら、対象のViewがNavigationBarの下に潜り込んでメニューバーなどが見えなくなりました。
これを解消するべく調べてみたら以下の記事がヒット↓

qiita.com

// PagingViewController

override func viewDidLoad() {
        
        super.viewDidLoad()
        
        self.navigationController?.navigationBar.isTranslucent = false
    }

これを参考にPagingViewControllerにこんなコード追加したらとりあえず直ったのですが、isTranslucentってプロパティは何ぞや?ということで少し調べてみました。

UINavigationController.navigationBar.isTranslucentについて

これはUINavigationBar、のプロパティで、ナビゲーションバーが半透明になったときにナビゲーションバーの下のコンテンツを表示するように設定します。デフォルト値はtrueです。

developer.apple.com

このデフォルト値がtrueなのにも関わらず、普通にナビゲーションバーを設置しても後ろが透過されてるように見えないのは、

  • レイアウトの中に不透明なナビゲーションバーが含むかどうかを示すextendedLayoutIncludesOpaqueBarsというプロパティのデフォルト値がfalseである
  • 通常SafeAreaはバーの下から設定されている
  • ナビゲーションバーの後ろはデフォルト背景が設定されている といった理由があります。

つまり、isTranslucentがtrueであることを活かしNavigationBarを透過させて下のコンテンツを表示するには、まずextendedLayoutIncludesOpaqueBarsプロパティをtrueにする必要がありそうです。 実は通常はこの設定だけでナビゲーションバーの下のコンテンツが見えるようになるんですが、それが叶うのはedgesForExtendedLayoutというプロパティがデフォルトで.allであるということが前提としてあるためです。

edgesForExtendedLayoutは端的にいうと、Viewがどの端まで伸びているかを示すもので、以下の項目があります。

public static var top: UIRectEdge { get }

public static var left: UIRectEdge { get }

public static var bottom: UIRectEdge { get }

public static var right: UIRectEdge { get }

public static var all: UIRectEdge { get }

デフォルトは.allに設定されています。StoryBoardからも設定できて、複数項目も設定できます。全部選ぶと.allと同じとみなされるみたいです。

ここまでをまとめると、通常であればisTranslucentがtrueであってもナビゲーションバーの下にViewが潜り込んでしまうことは無いはずなんですが、外部のライブラリ使ったりすると、意図せずしてデフォルト設定が変わっちゃってたりすることもあります。 そんなときに、isTranslucentをfalseに設定してあげると、

  • ナビゲーションバーが無条件に透過されなくなる
  • ナビゲーションバーが表示されている状態では、ViewControllerのビューの描画範囲が狭くなる

となり、潜り込んじゃったViewをちゃんと見ることができるようになるみたいです。

ちなみにこれは、TabBarなども持ってるプロパティです。

注意点

この設定を変えると、該当するNavigationController下にある全てのViewに影響が出るので、設定を変えたView以外のViewでレイアウトに多少の影響が出る可能性があります。(ちなみに私はこれいじって他のViewが崩れました)
設定を全部で統一した上で開発を進めるか、viewWillAppearとかでViewを描画するたびに設定してあげるかすると良さそうです。

間違ってたり足りなかったりしたらご指摘お願いします!