如何以编程方式获取iOS状态栏高度

288

我知道目前iPhone/iPad的状态栏(包括时间、电池和网络连接)在非Retina屏幕上为20像素,在Retina屏幕上为40像素,但为了未来使我的应用更具可靠性,我希望能够在不硬编码数值的情况下确定此高度。是否可能通过编程方式来计算状态栏的高度?

16个回答

517

[UIApplication sharedApplication].statusBarFrame.size.height。但由于所有尺寸都是以点为单位而非像素,状态栏高度始终等于20。

更新:看到这个答案被认为有用,我应该详细说明一下。

状态栏的高度确实等于20.0f点,除了以下情况:

  • 使用setStatusBarHidden:withAnimation:方法隐藏状态栏,此时状态栏的高度为0.0f点;
  • 如@Anton在这里指出,在手机应用程序之外接听电话或录音期间,状态栏高度为40.0f点。

还有一种情况是状态栏影响视图的高度。通常,视图的高度等于给定方向的屏幕尺寸减去状态栏高度。但是,如果在视图显示后对状态栏进行动画处理(显示或隐藏),状态栏将更改其框架,但视图不会,您需要在状态栏动画期间手动调整视图大小(或在动画期间进行调整,因为状态栏高度在动画开始时设置为最终值)。

更新2:还有一种用户界面方向的情况。状态栏不遵守方向值,因此纵向模式的状态栏高度值是[UIApplication sharedApplication].statusBarFrame.size.height(是的,默认方向始终是纵向的,无论您的应用信息.plist说了什么),而横向模式的状态栏高度为[UIApplication sharedApplication].statusBarFrame.size.width。要在UIViewController之外确定UI的当前方向并且self.interfaceOrientation不可用,请使用[UIApplication sharedApplication].statusBarOrientation

iOS7更新。即使状态栏的外观样式发生了变化,但它仍然存在,其框架仍然保持相同的行为。我得到的唯一有趣的关于状态栏的发现是:您的UINavigationBartiled背景也将铺设到状态栏,因此您可以实现一些有趣的设计效果或者只是给状态栏上色。这也不会以任何方式影响状态栏高度。

导航栏 tiled 背景也被铺设到状态栏


6
这种方法可产生1024 (iOS7)。 - Marc
2
是的,正如Marc所指出的,在iOS7上它有时会产生1024,有时会产生20。因此,这不再是一种确定高度的绝对可靠的方法。我怀疑这是因为iOS 7上状态栏透明的特性。可能是因为它首先进入全屏模式,然后再调整大小。因此,如果您的应用程序在此过渡期间查询,您可能会得到错误的值。也许在iOS 7上稍微延迟调用此方法可能会有所帮助。 - Deepak G M
1
有这样一种情况,状态栏高度可能为零。如果 supportedInterfaceOrientations() 返回UIInterfaceOrientation(错误的结果但没有编译器错误)而不是 UIInterfaceOrientationMask,而且一个视图控制器被呈现和取消呈现,状态栏高度将变为零。 - Cymric
5
iPhone X 的状态栏将会更高。 - pre
2
@pre 是的,iPhone X使用44。 - Sti
显示剩余10条评论

104

请按照Martin在获取iPhone状态栏高度问题中的建议进行操作。

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

而在Swift中

func statusBarHeight() -> CGFloat {
    let statusBarSize = UIApplication.shared.statusBarFrame.size
    return Swift.min(statusBarSize.width, statusBarSize.height)
}

看起来像是一个hack,但实际上非常可靠。无论如何,这是唯一有效的解决方案。

旧答案

以下代码应该放在您的UIViewController子类中,几乎可以支持横向。但是,我注意到一个特殊情况(从右边旋转>不支持的倒立>左边),它不能工作(切换高度和宽度)。

BOOL isPortrait = self.interfaceOrientation == UIInterfaceOrientationPortrait;
CGSize statusBarSize = [UIApplication sharedApplication].statusBarFrame.size;
CGFloat statusBarHeight = (isPortrait ? statusBarSize.height : statusBarSize.width);

这不是正确的。当您旋转设备时,状态栏的高度不会改变。宽度可能会改变,但上面的代码没有显示这一点,而原始问题也不是关于宽度的。 - lehn0058
1
你说得没错,“当你旋转设备时,状态栏的高度不会改变。” 但是,正如Ash的回答所述,“在横向模式下,你可能会发现宽度和高度被交换了。” 上面的代码已经考虑到了这一点。 - ma11hew28
这是一个我现在也看到的有趣问题。在我看来,这似乎是苹果方面的一个错误,但仍需要加以考虑。 - lehn0058
2
@lehn0058 这不是一个bug,这是苹果内部处理状态栏的方式。它附加在窗口上,并且该窗口使用变换进行旋转。 statusBarFrame 返回的是变换之前的值。 - Léo Natan
1
它作为一个属性看起来更好 :D var statusBarHeight: CGFloat - Pablo A.

23

试试这个:

CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;

1
不同方向返回的高度不同,这很奇怪。 - atastrophic
1
是的,如果旋转为横向,则[[UIApplication sharedApplication] statusBarFrame].size.height和[[UIApplication sharedApplication] statusBarFrame].size.width的值会交换。 - Guntis Treulands

21

Swift 3或Swift 4:

UIApplication.shared.statusBarFrame.height

10

虽然状态栏通常是20pt高,但在某些情况下可能会增加一倍:

  • 当您正在进行电话通话时(这是非常常见的情况);
  • 当语音记录器、Skype或类似的应用程序在后台使用麦克风时;
  • 当个人热点被激活时;

只需尝试一下,您就会看到自己。将高度硬编码为20pt通常有效,但也有例外。

所以我支持H2CO3的答案:

statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;

10

编辑 iOS 11中确定视图内容顶部位置的方法是使用UIView的safeAreaLayoutGuide。详见UIView文档

废弃答案 如果你在针对iOS 7及以上版本开发,UIViewController文档建议使用viewController的topLayoutGuide属性获取状态栏底部或导航栏底部(如果也可见),这可能会有用,而且比之前的许多解决方案更加正式。


10

对于iOS 13,您可以使用:

UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame.height

但是keyWindow在iOS 13中已被弃用。这从来都不是正确的答案。 - undefined

5

不要忘记状态栏的框架将在屏幕坐标空间中!如果您以横向模式启动,可能会发现宽度和高度被交换了。如果您支持横向方向,请强烈建议您使用此代码版本:

CGRect statusBarFrame = [self.window convertRect:[UIApplication sharedApplication].statusBarFrame toView:view];

您可以直接读取statusBarFrame的height属性。 在这种情况下,“View”应该是您希望使用这些测量值的视图,很可能是应用程序窗口的根视图控制器。
顺便提一下,如果状态栏被故意隐藏,不仅在进行电话通话时状态栏可能更高,而且还可能为零。

这并没有给我正确的高度。但是,我找到了一种适合我的不同方法:https://dev59.com/pWcs5IYBdhLWcg3wRB3h#16598350 - ma11hew28
是的,这段代码现在已经很老了,所以可能不再是一个有效的答案。个人而言,由于自动布局的存在,我再也没有必要检查状态栏的高度了。 - Ash

3

UIApplication.shared.statusBarFrame.heightiOS 13中已被弃用

'statusBarFrame'在iOS 13.0中已被弃用:改用窗口场景的statusBarManager属性。

你可以像下面这样在iOS 13中检索状态栏高度:

let statusBarHeight = view.window?.windowScene?.statusBarManager?.statusBarFrame.height

NB!这是可选的,所以请确保你有正确的备用方案。


3
    var statusHeight: CGFloat!
    if #available(iOS 13.0, *) {
         statusHeight = UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame.height
    } else {
        // Fallback on earlier versions
        statusHeight = UIApplication.shared.statusBarFrame.height
    }

iOS 13的代码从来都不正确,因为在iOS 13中已经弃用了keyWindow - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接