62

I need to resize some elements in relation to the height of the iPhone's Status Bar. I know that the status bar is usually 20 points high but this isn't the case when it's in tethering mode. It gets doubled to 40. What is the proper way to determine it's height? I've tried

[[UIApplication sharedApplication] statusBarFrame]

but it gives me 20 x 480 in landscape which is correct but then it gives me 320 x 40 in portrait. Why isn't it giving me the opposite of that (40 x 320)?

Bruno Bieri
  • 9,724
  • 11
  • 63
  • 92
Kyle Decot
  • 20,715
  • 39
  • 142
  • 263

7 Answers7

81

The statusBarFrame returns the frame in screen coordinates. I believe the correct way to get what this corresponds to in view coordinates is to do the following:

- (CGRect)statusBarFrameViewRect:(UIView*)view 
{
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];

    CGRect statusBarWindowRect = [view.window convertRect:statusBarFrame fromWindow: nil];

    CGRect statusBarViewRect = [view convertRect:statusBarWindowRect fromView: nil];

    return statusBarViewRect;
}

Now in most cases the window uses the same coordinates as the screen, so [UIWindow convertRect:fromWindow:] doesn't change anything, but in the case that they might be different this method should do the right thing.

ThomasW
  • 16,981
  • 4
  • 79
  • 106
  • 2
    Calling this method in `-[UIViewController viewWillAppear:]` didn't work. Two issues: 1. The view's window is `nil` then. 2. Even when I preceded the call to `-[UIWindow convertRect:fromWindow:]` with `if (view.window)`, when I popped back to the view controller in landscape mode, the statusBarFrame had width & height switched and the call to `-[UIView convertRect:fromView:]` didn't switch them back correctly. – ma11hew28 May 20 '13 at 23:50
  • @MattDiPasquale Why not call it in `viewDidAppear:` instead? – ThomasW May 21 '13 at 00:50
  • 1
    Because, I'm adjusting `self.collectionView.contentInset` based on `[UIApplication sharedApplication].statusBarFrame`. If I adjust it after the view appears, then you can see it jump. So, I must adjust it before the view appears. – ma11hew28 May 23 '13 at 00:06
16

Did you do it like this:

CGRect rect;

rect = [[UIApplication sharedApplication] statusBarFrame];
NSLog(@"Statusbar frame: %1.0f, %1.0f, %1.0f, %1.0f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
o15a3d4l11s2
  • 3,969
  • 3
  • 29
  • 40
7

EDIT The iOS 11 way to work out where to put the top of your view content is UIView's safeAreaLayoutGuide See UIView Documentation.

DEPRECATED ANSWER If you're targeting iOS 7+, The documentation for UIViewController advises that the viewController's topLayoutGuide property gives you the bottom of the status bar, or the bottom of the navigation bar, if it's also visible. That may be of use, and is certainly less hack than many of the previous solutions.

Joshua J. McKinnon
  • 1,696
  • 1
  • 18
  • 29
6

This method works for portrait & landscape orientation.

-(float) statusBarHeight
{
    CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
    return MIN(statusBarSize.width, statusBarSize.height);
}

// example call
float statusBarHeight = [self statusBarHeight];
David Douglas
  • 10,377
  • 2
  • 55
  • 53
6

You could test which is the lesser of the two values, that will be the real height.

Martin
  • 231
  • 2
  • 4
5

Swift 2:

let statusBarHeight = UIApplication.sharedApplication().statusBarFrame.height

Swift 3 or Swift 4:

let statusBarHeight = UIApplication.shared.statusBarFrame.height

Advice: Don't forget to inject the UIApplication.shared do not just use the singleton in your code.

iAj
  • 3,787
  • 1
  • 31
  • 34
nsmeme
  • 221
  • 4
  • 1
0

Here is the Swift version if anyone needs it:

var screenStatusBarHeight: CGFloat {
    return UIApplication.sharedApplication().statusBarFrame.height
}

This is included as a standard variable in:

https://github.com/goktugyil/EZSwiftExtensions

Disclaimer: Its my repo

Esqarrouth
  • 38,543
  • 21
  • 161
  • 168