Skip to main content
すっさんぽ
  1. Posts/

画面遷移時にUINavigationBarが勝手に表示される現象への対処法

NavigationBarが非表示になっているViewControllerから、SwiftUIを含む別のViewControllerへ遷移するとき、NavigationBarが勝手に表示されてしまう現象に遭遇しました。 これに対処しようとして、navigationController?.navigationBar.isHidden = truenavigationController?.setNavigationBarHidden(true, animated: false) を呼んでも、全く解決しませんでした。 この現象を回避するために、今回は、UIHostingControllerを継承したカスタマイズしたクラスを実装して対応しました。

現象の詳細 #

  • NavigationBarを非表示にしている画面(画面A)から別の画面(画面B)へpush遷移するとき、NavigationBarが表示済みになった画面Bがスライドしてくる
  • 画面Bは、UIHostingControllerでSwiftUIを流し込んでいる
    • UIHostingControllerを使わない画面では、この問題は発生しない
  • 以下の処理を呼んでいても、NavigationBarが表示された画面がスライドしてくる
    • navigationController?.navigationBar.isHidden = true
    • navigationController?.setNavigationBarHidden(true, animated: false)
    • navigationBarHidden(true)(SwiftUIのViewで)

この現象が発生する条件は、よくわかっていません。 発生するアプリと、発生しないアプリがあります。同じXcodeのバージョンを使っていてもです。

勝手にNavigationBarが表示されてしまう原因 #

UIHostingControllerが、その内部処理でNavigationBarのisHiddenfalseにしているようです。 また、そのタイミングは viewWillAppear ということがわかりました。

対処・実装 #

UIHostingControllerを継承したカスタムクラスを用意して、viewWillAppearの挙動を変更しました。

final class UIHostingControllerCustomized <Content>: UIHostingController<AnyView> where Content : View {

    private let preferredNavigationBarHidden: Bool

    public init(preferredNavigationBarHidden: Bool, rootView: Content) {
        self.preferredNavigationBarHidden = preferredNavigationBarHidden
        super.init(rootView: AnyView(rootView.navigationBarHidden(preferredNavigationBarHidden)))
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)  // ← ここで isHiddenが強制的にfalseになることがある

        // 意図した設定値になっていない場合は、
        // `isHidden`の値をセットし直す
        if navigationController?.isNavigationBarHidden != preferredNavigationBarHidden {
            navigationController?.navigationBar.isHidden = preferredNavigationBarHidden
            navigationController?.setNavigationBarHidden(preferredNavigationBarHidden, animated: false)
        }
    }
}

このクラスを、いつものUIHostingControllerと同じように使うことで、この現象を回避することができました。

// ViewController側の実装
override func viewDidLoad() {
    super.viewDidLoad()
    let vc = UIHostingControllerCustomized(preferredNavigationBarHidden: true,
                                           rootView: MyView())
    addChild(vc)
    vc.view.frame = view.bounds
    view.addSubview(vc.view)
    vc.didMove(toParent: self)
}

参考にしたページ #