Swift 5:iOS 15、Xcode 13.2.1环境下适配屏幕旋转的状态栏颜色管理问题
解决iOS横屏模式下状态栏消失+导航区域被遮挡的问题
嗨,我来帮你搞定这个横屏状态栏的麻烦!你的问题根源在于自定义状态栏视图没有跟随屏幕旋转更新尺寸,加上iOS13+横屏时默认可能隐藏状态栏,才导致了这两个问题。咱们一步步来解决:
第一步:先确保横屏时状态栏能显示出来
首先,在你的Info.plist里确认View controller-based status bar appearance设置为YES(这是默认值,但最好检查一下)。然后在每个需要显示状态栏的ViewController里重写两个属性:
override var preferredStatusBarStyle: UIStatusBarStyle { // 根据你的需求选,比如浅色文字用.lightContent,深色用.darkContent return .lightContent } override var prefersStatusBarHidden: Bool { // 这里返回false,强制横屏时也显示状态栏 return false }
这样就能保证横屏时状态栏不会消失啦。
第二步:替换自定义状态栏颜色的实现(推荐用系统原生方式)
你之前用添加UIView的方式很容易出现旋转适配问题,其实iOS13+官方已经提供了更优雅的方式:如果你的页面用了UINavigationController,直接设置导航栏的外观就能同步状态栏的颜色,完全不用自定义视图:
override func viewDidLoad() { super.viewDidLoad() if #available(iOS 13.0, *) { let navBarAppearance = UINavigationBarAppearance() // 设置导航栏(包括状态栏下方区域)的背景色 navBarAppearance.backgroundColor = UIColor(named: "BackGroundColor") // 设置导航栏文字颜色(和状态栏文字颜色对应) navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white] navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white] // 把这个外观应用到所有状态的导航栏 navigationController?.navigationBar.standardAppearance = navBarAppearance navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance navigationController?.navigationBar.compactAppearance = navBarAppearance } else { // iOS12及以下的兼容写法 navigationController?.navigationBar.barTintColor = UIColor(named: "BackGroundColor") navigationController?.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white] } }
这种方式完全适配横竖屏旋转,不会出现遮挡问题,而且符合苹果的设计规范。
如果必须自定义状态栏背景(不用导航栏的情况)
要是你的页面没有导航栏,必须用自定义视图来做状态栏背景,那得修改原来的代码,添加旋转监听来更新视图的frame,还要避免重复添加视图:
class YourViewController: UIViewController { // 保存状态栏背景视图的引用,方便后续更新和移除 private var statusBarBackgroundView: UIView? override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setupStatusBarBackground() // 监听屏幕旋转通知,更新视图尺寸 NotificationCenter.default.addObserver(self, selector: #selector(updateStatusBarFrame), name: UIDevice.orientationDidChangeNotification, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 移除监听,避免内存泄漏 NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil) // 移除背景视图,防止返回再进入时重复添加 statusBarBackgroundView?.removeFromSuperview() statusBarBackgroundView = nil } private func setupStatusBarBackground() { guard let statusBarFrame = UIApplication.shared.currentScene?.statusBarManager?.statusBarFrame else { return } let statusBarView = UIView(frame: statusBarFrame) statusBarView.backgroundColor = UIColor(named: "BackGroundColor") UIApplication.shared.windows.first?.addSubview(statusBarView) self.statusBarBackgroundView = statusBarView } @objc private func updateStatusBarFrame() { // 旋转后重新获取状态栏的frame并更新视图 guard let statusBarFrame = UIApplication.shared.currentScene?.statusBarManager?.statusBarFrame else { return } statusBarBackgroundView?.frame = statusBarFrame } }
为什么原来的代码会出问题?
你之前的代码在viewWillAppear里创建一次状态栏视图,横屏时屏幕旋转了,但这个视图的frame还是竖屏时的尺寸,所以就会变成一个小矩形挡在导航栏左侧;另外没有设置prefersStatusBarHidden,导致横屏时系统默认隐藏了状态栏,才会出现“状态栏消失”的情况。
内容的提问来源于stack exchange,提问作者Michael




