You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动