How to get the status bar height in iOS 13?
IosIos13Ios Problem Overview
In iOS 13 UIApplication.shared.statusBarFrame.height
warns
> 'statusBarFrame' was deprecated in iOS 13.0: Use the statusBarManager > property of the window scene instead.
How do you get the status bar height without using a deprecated API in iOS 13?
Ios Solutions
Solution 1 - Ios
As the warning hints, you can access the statusBarManager
which has a statusBarFrame
property. This is defined on your UIWindow
's windowScene
.
let height = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
Solution 2 - Ios
Try, I have tried it.
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
let height = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
Solution 3 - Ios
Solution:
This seems to work without any warning in iPhoneX+ devices as well.
Swift 4.2 / 5
if #available(iOS 13.0, *) {
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
statusBarHeight = UIApplication.shared.statusBarFrame.height
}
Try it. Hope it Helps.
Solution 4 - Ios
UIApplication.shared.windowswindows was deprecated in iOS 15.0
iOS 15
let statusBarHeight = UIApplication.shared.connectedScenes
.filter {$0.activationState == .foregroundActive }
.map {$0 as? UIWindowScene }
.compactMap { $0 }
.first?.windows
.filter({ $0.isKeyWindow }).first?
.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
Solution 5 - Ios
var statusBarHeight: CGFloat = 0
if #available(iOS 13.0, *) {
statusBarHeight = UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
statusBarHeight = UIApplication.shared.statusBarFrame.height
}
Solution 6 - Ios
I had the same problem as MMV (see their comment on Jordan H's answer), view.window?.windowScene?.statusBarManager?.statusBarFrame.height
returned nil near the launch of my app. Specifically view.window
returned nil. I then tried searching through the windows property on UIApplication.shared:
for window in UIApplication.shared.windows
This returned two windows in my case. Both of the windows had equal, non-nil status bar heights. I'm not sure why there were two windows, but at least both had the same status bar heights. I accessed the status bar heights like so:
if let height = window.windowScene?.statusBarManager?.statusBarFrame.height
I decided in my case that since there could possibly be different heights to take the largest of the heights for my code. Here is the code I used for my application:
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
}()
Hope this helps someone!
Solution 7 - Ios
For the latest method of getting statusBarHeight, is as follows:
private lazy var statusBarHeight: CGFloat = {
var statusBarHeight: CGFloat = 0
if #available(iOS 13.0, *) {
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
statusBarHeight = UIApplication.shared.statusBarFrame.height
}
return statusBarHeight
}()
Solution 8 - Ios
Learning from the great answers already given here, using connectScenes
from UIApplication
, and we can make an extension:
extension UIApplication {
var statusBarHeight: CGFloat {
connectedScenes
.compactMap {
$0 as? UIWindowScene
}
.compactMap {
$0.statusBarManager
}
.map {
$0.statusBarFrame
}
.map(\.height)
.max() ?? 0
}
}
Usage:
let height = UIApplication.shared.statusBarHeight
Solution 9 - Ios
For Objective-C
I'm not sure what is alternative of filter in OC, so I used a for loop to get keyWindow
. Well, the actual height I get in iPhone 12 is '47' and iPhone 8 with '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;
}
Solution 10 - Ios
for iOS 13:
in your 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
}
}
and if you want to pass the value to your View
s, you can set the value as Environment
and use it in your View
s. example:
first we need to create our environment key:
struct StatusBarSizeEnvironmentKey: EnvironmentKey {
public static let defaultValue: CGRect = CGRect()
}
extension EnvironmentValues {
public var statusBarSize: CGRect {
set { self[StatusBarSizeEnvironmentKey.self] = newValue }
get { self[StatusBarSizeEnvironmentKey] }
}
}
and set the value in 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))
}
}
Solution 11 - Ios
stolen from accepted answer:
guard let sbheight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height else {
assertionFailure("usage error: VC lifecyclewise it becomes available no earlier than viewDidAppear")
}
Solution 12 - Ios
For 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;
}
I think the above is OK too, @ChuckZHB's answer.