You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS纯代码UI:添加覆盖状态栏的LoaderOverlay且保留状态栏文字

解决LoaderOverlay显示时状态栏文字消失的问题

我来帮你搞定这个状态栏文字消失的坑!咱们先分析问题根源,再一步步修正:

问题核心

  1. 你用的UIApplication的statusBarView扩展依赖私有API("statusBar"这个key),iOS 13之后系统对状态栏结构做了调整,这种写法不仅不安全(可能过不了App Store审核),还会和你设置的窗口层级冲突。
  2. 你把window.windowLevel改成UIWindow.Level.statusBar,会让Loader窗口直接覆盖在状态栏窗口之上,导致状态栏文字被完全遮挡。

解决方案步骤

1. 废弃私有API的状态栏背景设置

首先删掉setupNavigationBarStyle里的UIApplication.shared.statusBarView!.backgroundColor代码,同时移除那个UIApplication的statusBarView扩展。

因为你已经把UINavigationBar的isTranslucent设为false,状态栏会自动继承导航栏的barTintColor,不需要额外设置背景色。修改后的代码如下:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    setupNavigationBarStyle()
    window = UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    window?.rootViewController = UINavigationController(rootViewController: HeadlinesViewController(networkHelper: NetworkHelper.shared))
    return true
}

func setupNavigationBarStyle() {
    // 移除statusBarView相关私有API代码
    UINavigationBar.appearance().barTintColor = UIColor.navigationBarBackground
    UINavigationBar.appearance().tintColor = UIColor.navigationBarTint
    UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.navigationBarText]
    UINavigationBar.appearance().isTranslucent = false
    UITabBar.appearance().barTintColor = UIColor.navigationBarBackground
    UITabBar.appearance().tintColor = UIColor.navigationBarTint
    
    // 可选:调整状态栏文字颜色,根据导航栏背景色选择
    UINavigationBar.appearance().barStyle = .darkContent // 浅色背景用这个,深色背景用.default
}

2. 修改LoaderOverlay实现,避免修改窗口层级

不要直接操作window的层级,而是把Overlay添加到当前根控制器的view上,这样既能覆盖全屏(包括状态栏区域),又不会遮挡状态栏文字。修改后的LoaderOverlay代码:

public class LoaderOverlay{
    var overlayView = UIView()
    var activityIndicator = UIActivityIndicatorView()
    
    class var shared: LoaderOverlay {
        struct Static {
            static let instance:LoaderOverlay = LoaderOverlay()
        }
        return Static.instance
    }
    
    public func showOverlay() {
        // 获取当前窗口的根控制器视图
        guard let rootView = UIApplication.shared.keyWindow?.rootViewController?.view else { return }
        
        overlayView.removeFromSuperview() // 先移除旧的overlay,避免重复添加
        overlayView = UIView(frame: rootView.bounds)
        overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
        // 设置自动适配父视图尺寸变化
        overlayView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        activityIndicator.removeFromSuperview()
        activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
        activityIndicator.center = overlayView.center
        overlayView.addSubview(activityIndicator)
        activityIndicator.startAnimating()
        
        rootView.addSubview(overlayView)
        // 把overlay放到最上层,确保覆盖所有内容
        rootView.bringSubviewToFront(overlayView)
    }
    
    public func hideOverlayView() {
        activityIndicator.stopAnimating()
        overlayView.removeFromSuperview()
    }
}

为什么这样改?

  • 不再依赖私有API,避免审核风险,同时适配iOS 13+的系统变化。
  • 把Overlay添加到根控制器的view层级中,和状态栏属于同一window,不会覆盖状态栏的文字层;同时因为导航栏不透明,Overlay可以延伸到状态栏区域,完美实现你要的全屏覆盖效果。

内容的提问来源于stack exchange,提问作者Reimond Hill

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:49:35