iOS 15でNavigationBarとTabBarがデフォルトで透過される

iOS 15でNavigationBarとTabBarがデフォルトで透過される

iOS 15をXcode 13以上で開発していたところ、NavigationBarとTabBarの背景が透過されていることがわかりました。

NavigationBar
TabBar

どうやらXcode 13でビルドをした場合、iOS 15のNavigationBarとTabBarはデフォルトで背景が透過されるようです。

私のアプリでは透過ではなく、iOS 14以前と同じように背景色をつけたかったので、どう修正するのかを調べました。

開発環境

  • Xcode 13.2
  • iOS 15.2

NavigationBarをiOS 14以前と同じ見た目にする

背景色が透過されるようになった原因

UINavigationBarにはscrollEdgeAppearanceというプロパティがあります。
UINavigationBarAppearanceというNavigationBarの外観設定を司るクラスのインスタンスです。
Navigation ControllerがNavigation BarとScroll Viewを持っている場合で、Scroll Viewのコンテンツの端がNavigation Barに到達したときに外観設定が適応されます。

公式ドキュメントを読むと、scrollEdgeAppearanceはnilの場合に、standardAppearanceを利用するのですが、そのデータが背景を透明にするものになっているとのことです。
この適応はiOS 14以前では「大きなタイトル(ラージタイトル)」を持つNavigation Barのみでしたが、iOS 15ではすべてのNavigation Barに適応されたとのことです。

動作を確認したgifがこちらです。

Dec-29-2021-14-27-52

確かにスクロールでコンテンツが端に到達した場合は透明に、そうでない場合は背景色がつくようになっています。

ちなみに「大きなタイトル」を適応するにはprefersLargeTitlesをtrueにセットすればよいです。

navigationController?.navigationBar.prefersLargeTitles = true

UINavigationBarの外観設定の種類

UINavigationBarにはscrollEdgeAppearanceの他にstandardAppearancecompactAppearanceという外観設定のインスタンスが用意されています。
それぞれの使いみちは次の通りです。

  • standardAppearance: 通常のNavigationBarの外観設定
  • compactAppearance: iPhoneで横向きの場合のNavigationBarの外観設定
  • scrollEdgeAppearance: Scroll Viewのコンテンツの端がNavigation Barに到達したときの外観設定

詳細は以前ブログで解説しています。お時間のある方はこちらもご参照ください。

修正コード

次のようにコードをAppDelegateapplication(_:didFinishLaunchingWithOptions:)メソッドなどの必ずアプリが実行する場所に実装しましょう。
そうするとiOS 14と同じ外観になります。

if #available(iOS 15.0, *) {
    // disable UINavigation bar transparent
    let navigationBarAppearance = UINavigationBarAppearance()
    navigationBarAppearance.configureWithDefaultBackground()
    UINavigationBar.appearance().standardAppearance = navigationBarAppearance
    UINavigationBar.appearance().compactAppearance = navigationBarAppearance
    UINavigationBar.appearance().scrollEdgeAppearance = navigationBarAppearance
}

navigationBarAppearanceconfigureWithDefaultBackgroundでデフォルトの背景色を設定し、standardAppearancecompactAppearancescrollEdgeAppearanceに代入しています。

背景色を透明にしているのはscrollEdgeAppearanceですが、同じ設定をstandardAppearancecompactAppearanceにも適応して設定をそろえています。

こうすることでiOS 15でもiOS 14と同じ見た目にできます。

TabBarをiOS 14以前と同じ見た目にする

背景色が透過されるようになった原因

TabBarもscrollEdgeAppearanceがiOS 15から導入されました。

Navigation BarのscrollEdgeAppearanceはiOS 13から導入

用途はNavigation Barと同じです。
Tab Bar ControllerがTab BarとScroll Viewを持っている場合、Scroll Viewのコンテンツの端がTab Barに到達した場合の外観設定を行います。
nilの場合はstandardAppearanceを利用するのですが、そのデータが背景を透明にするものになっているため、iOS 15のみが背景透過されてしまいます。

scrollEdgeAppearance | Apple Developer Documentation

修正コード

Navigation Barと同じくAppDelegateapplication(_:didFinishLaunchingWithOptions:)メソッドなどの必ずアプリが実行する場所でscrollEdgeAppearanceにデフォルトの背景色を設定します。
そうするとiOS 14と同じ外観になります。

if #available(iOS 15.0, *) {
    // disable UITab bar transparent
    let tabBarAppearance: UITabBarAppearance = UITabBarAppearance()
    tabBarAppearance.configureWithDefaultBackground()
    UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance
    UITabBar.appearance().standardAppearance = tabBarAppearance
}

このコードではstandardAppearanceも同じ設定でそろえています。
standardAppearanceは通常の場合の外観設定に使われるものです。

まとめ

iOS 15によるNavigation BarとTab Barの外観のデフォルト値が背景透明になる現象と、iOS 14以前の見た目に戻すコードを紹介しました。

OSが変わるとデフォルトの動きも変わることがあるのは仕方がないことですね。
一つずつ見つけて直していきましょう。

参考URL

宣伝

インプレスR&D社より「一冊でマスター!Swift Concurrency入門」が発売中です。
Swift Concurrencyを網羅的に学べ、さらに既存アプリへの適応方法も解説しています。
日本語で体系的に学べる解説本は他にありません。
ぜひチェックしてみてください!

一冊でマスター!Swift Concurrency入門

一冊でマスター!Swift Concurrency入門