iOS13中如何获取状态栏高度?

How to get the status bar height in iOS 13?

在iOS 13 UIApplication.shared.statusBarFrame.height警告

'statusBarFrame' was deprecated in iOS 13.0: Use the statusBarManager property of the window scene instead.

如何在不使用 iOS 13 中已弃用的 API 的情况下获得状态栏高度?

如警告提示,您可以访问 statusBarManager,其中有一个 statusBarFrame 属性。这是在您的 UIWindowwindowScene.

上定义的
let height = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0

试试,我试过了

let window = UIApplication.shared.windows.filter {[=10=].isKeyWindow}.first        
let height = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0

我遇到了与 MMV 相同的问题(请参阅他们对 Jordan H 的回答的评论),view.window?.windowScene?.statusBarManager?.statusBarFrame.height 在我的应用程序启动时返回 nil。具体来说 view.window 返回 nil。然后我尝试在 UIApplication.shared:

上搜索 windows 属性
for window in UIApplication.shared.windows

在我的例子中,这返回了两个 windows。两个 windows 都有相等的非零状态栏高度。我不确定为什么会有两个 windows,但至少两者的状态栏高度相同。我像这样访问状态栏高度:

if let height = window.windowScene?.statusBarManager?.statusBarFrame.height

我决定在我的例子中,因为可能有不同的高度来为我的代码取最大的高度。这是我用于我的应用程序的代码:

let statusBarHeight: CGFloat = {
    var heightToReturn: CGFloat = 0.0
         for window in UIApplication.shared.windows {
             if let height = window.windowScene?.statusBarManager?.statusBarFrame.height, height > heightToReturn {
                 heightToReturn = height
             }
         }
    return heightToReturn
}()

希望这对某人有所帮助!

var statusBarHeight: CGFloat = 0
if #available(iOS 13.0, *) {
    statusBarHeight = UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
    statusBarHeight = UIApplication.shared.statusBarFrame.height
}

解法:

这似乎在 iPhoneX+ 设备中也没有任何警告。

Swift 4.2 / 5

if #available(iOS 13.0, *) {
    let window = UIApplication.shared.windows.filter {[=10=].isKeyWindow}.first
    statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
    statusBarHeight = UIApplication.shared.statusBarFrame.height
}

试试吧。希望对你有帮助。

对于 iOS 13:

在你的 SceneDelegate:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
 if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    let statusBarSize = windowScene.statusBarManager!.statusBarFrame
    ...// initialize your root view controller
 }
}

如果您想将值传递给您的 View,您可以将值设置为 Environment 并在您的 View 中使用它。示例:

首先我们需要创建我们的环境密钥:

struct StatusBarSizeEnvironmentKey: EnvironmentKey {
   public static let defaultValue: CGRect = CGRect()
}

extension EnvironmentValues {
  public var statusBarSize: CGRect {
    set { self[StatusBarSizeEnvironmentKey.self] = newValue }
    get { self[StatusBarSizeEnvironmentKey] }
  }
}

并在SceneDelegate中设置值:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
 if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    let statusBarSize = windowScene.statusBarManager!.statusBarFrame
    window.rootViewController = UIHostingController(rootView: YourView()
             .environment(\.statusBarSize, statusBarSize))
 }
}

从这里已经给出的很好的答案中学习,使用 UIApplication 中的 connectScenes,我们可以进行扩展:

extension UIApplication {
    var statusBarHeight: CGFloat {
        connectedScenes
            .compactMap {
                [=10=] as? UIWindowScene
            }
            .compactMap {
                [=10=].statusBarManager
            }
            .map {
                [=10=].statusBarFrame
            }
            .map(\.height)
            .max() ?? 0
    }
}

用法:

let height = UIApplication.shared.statusBarHeight

最新获取​​statusBarHeight的方法如下:

    private lazy var statusBarHeight: CGFloat = {
        var statusBarHeight: CGFloat = 0
        if #available(iOS 13.0, *) {
            let window = UIApplication.shared.windows.filter {[=10=].isKeyWindow}.first
            statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
        } else {
            statusBarHeight = UIApplication.shared.statusBarFrame.height
        }
        return statusBarHeight
    }()

从已接受的答案中窃取:

guard let sbheight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height else {
     assertionFailure("usage error: VC lifecyclewise it becomes available no earlier than viewDidAppear")
}

对于Objective-C

我不确定 OC 中过滤器的替代方法是什么,所以我使用 for 循环来获取 keyWindow。好吧,我在 iPhone 12 中得到的实际高度是“47”,在 iPhone 8 中得到的实际高度是“20”。

    CGFloat statusBarHeight;
    if (@available(iOS 13, *)) {
        NSArray *windows = UIApplication.sharedApplication.windows;
        UIWindow *keyWindow = nil;
        
        for (UIWindow *window in windows) {
            if (window.isKeyWindow) {
                keyWindow = window;
                break;
            }
        }
        statusBarHeight = keyWindow.windowScene.statusBarManager.statusBarFrame.size.height;
        NSLog(@"statusBarHeight: %f", statusBarHeight);
    } else {
        statusBarHeight = UIApplication.sharedApplication.statusBarFrame.size.height;
    }

UIApplication.shared.windowswindows 在 iOS 15.0

中被弃用

iOS 15

 let statusBarHeight = UIApplication.shared.connectedScenes
        .filter {[=10=].activationState == .foregroundActive }
        .map {[=10=] as? UIWindowScene }
        .compactMap { [=10=] }
        .first?.windows
        .filter({ [=10=].isKeyWindow }).first?
        .windowScene?.statusBarManager?.statusBarFrame.height ?? 0

对于Objective-C

- (CGFloat)statusBarHeight{
    UIWindowScene * scene = nil;
    for (UIWindowScene* wScene in [UIApplication sharedApplication].connectedScenes){
        if (wScene.activationState == UISceneActivationStateForegroundActive){
            scene = wScene;
            break;
        }
    }
    return scene.statusBarManager.statusBarFrame.size.height;
}

我觉得上面的也OK,@ChuckZHB的回答