tofucodes diary

にほんごのほう

SideMenuライブラリでツールバーの見た目を変更できない原因と解決方法

github.com

問題

アプリ側のステータスバーの見た目とSideMenuで表示するメニュー側のステータスバーの見た目を変えるために、以下のような実装を行なった。

import SideMenu

let menuLeftNavigationController = UISideMenuNavigationController(rootViewController: MenuViewController())
SideMenuManager.default.menuLeftNavigationController = menuLeftNavigationController
SideMenuManager.default.menuWidth = 280
SideMenuManager.default.menuPresentMode = .viewSlideInOut
class MenuViewController: UIViewController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

しかしMenuViewControllerのpreferredStatusBarStyleは実行されず、期待した動作にならなかった。

原因

SideMenuのコードを読んでみると、SideMenuManagerにNavigationControllerをセットしたタイミングで、そのNavigationControllerのmodalPresentationStyle.overFullScreenに変更されてしまっていた。

    fileprivate func setupNavigationController(_ forMenu: UISideMenuNavigationController?, leftSide: Bool) {
        guard let forMenu = forMenu else {
            return
        }
        
        forMenu.transitioningDelegate = transition
        forMenu.modalPresentationStyle = .overFullScreen
        forMenu.leftSide = leftSide
        ...

https://github.com/jonkykong/SideMenu/blob/1b6b8c446c10240b6bffb7c0ba1e18424791c74f/Pod/Classes/SideMenuManager.swift#L238

公式ドキュメントによると、ViewControllerをpresent(_:animated:completion:)で表示する時、ステータスバーの見た目のコントロールは表示する側から表示される側に移る。ただし表示される側のmodalPresentationStyle.fullScreenの時だけね🤪

When you present a view controller by calling the present(_:animated:completion:) method, status bar appearance control is transferred from the presenting to the presented view controller only if the presented controller's modalPresentationStyle value is UIModalPresentationStyle.fullScreen.

modalPresentationCapturesStatusBarAppearance - UIViewController | Apple Developer Documentation

解決法

SideMenuのNavigationControllerのmodalPresentationCapturesStatusBarAppearanceをtrueに設定する。

// modalPresentationStyle become .overFullScreen as set to menuLeftNavigationController.
// Set this property true in order to make sure that status bar appearance control
// is transferred from the presenting to the presented view controller.
menuLeftNavigationController.modalPresentationCapturesStatusBarAppearance = true

こうすることでMenuViewControllerのmodalPresentationStyleの値に関わらずoverrideしたpreferredStatusBarStyleが実行されるようになり期待した動作になる。