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

如何获取iOS中NavigationBar默认高度(或maxY)及大/小标题状态下高度?

嘿,我来帮你搞定这个导航栏高度的问题!针对你提到的需求——获取UINavigationBar的默认高度(优先maxY值),还要区分普通标题和大标题状态,我整理了一套靠谱的解决方案,顺便帮你排查下之前frame.maxY返回值异常的原因。

先搞清楚核心问题:为什么直接取frame.maxY不对?

你遇到的返回值异常,大概率是这两个原因:

  1. 布局时机不对:viewDidLoad时视图还没完成布局,viewWillAppear也可能因为导航栏动画(比如大标题展开/折叠)导致frame未更新;
  2. 透明背景的影响:当你把导航栏设为透明时,isTranslucent默认是true,此时导航栏的frame会包含状态栏区域(刘海屏就是24pt+导航栏本身高度),所以返回的maxY会比你预期的“导航栏本身高度”高很多。

分场景获取高度/MaxY值

1. 获取静态默认高度(不考虑动态变化)

如果你只是想知道系统默认的高度值,不用实时监听变化,可以用UINavigationBarAppearance来获取,这是iOS 13+最推荐的方式:

// 普通标题(compact)状态下的导航栏本身高度
let compactNavBarHeight = UINavigationBarAppearance().compactLayoutSize.height
// 大标题(large)展开状态下的导航栏本身高度
let largeNavBarAppearance = UINavigationBarAppearance()
largeNavBarAppearance.configureWithLargeTitle()
let largeNavBarHeight = largeNavBarAppearance.layoutSize.height

系统默认值:普通标题是44pt,大标题展开是96pt。

2. 获取实时的MaxY值(相对于导航控制器的View)

如果你需要的是导航栏frame的maxY(也就是从导航控制器View顶部到导航栏底部的距离),要在布局完成后获取,比如viewDidAppear或者layoutSubviews中:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    // 获取当前导航栏的maxY
    if let navBarFrame = navigationController?.navigationBar.frame {
        print("当前导航栏maxY: \(navBarFrame.maxY)")
    }
    
    // 如果需要区分屏幕顶部到导航栏底部的距离(包含状态栏),可以这么算:
    let statusBarHeight = UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
    let currentNavBarHeight = navigationController?.navigationBar.bounds.height ?? 0
    let screenToNavBarBottom = statusBarHeight + currentNavBarHeight
    print("屏幕顶部到导航栏底部的距离: \(screenToNavBarBottom)")
}
  • 刘海屏普通标题:maxY是68pt(24pt状态栏+44pt导航栏);
  • 刘海屏大标题展开:maxY是120pt(24pt状态栏+96pt导航栏);
  • 非刘海屏的话,状态栏高度换成20pt即可。

3. 监听大标题折叠/展开的动态高度变化

如果你的页面支持大标题,需要实时获取折叠/展开状态下的高度,可以用KVO监听导航栏的bounds变化:

override func viewDidLoad() {
    super.viewDidLoad()
    // 开启大标题模式
    navigationController?.navigationBar.prefersLargeTitles = true
    // 添加KVO监听
    navigationController?.navigationBar.addObserver(self, forKeyPath: "bounds", options: [.new], context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "bounds", let navBar = object as? UINavigationBar {
        print("导航栏高度变化: \(navBar.bounds.height),当前maxY: \(navBar.frame.maxY)")
    }
}

deinit {
    // 记得移除监听
    navigationController?.navigationBar.removeObserver(self, forKeyPath: "bounds")
}

额外提醒

  • 如果你自定义了导航栏的背景(比如Effect View),建议把Effect View的高度和导航栏的bounds.height绑定,而不是硬编码,这样能适配所有状态;
  • iOS 13+不要用UIApplication.shared.statusBarFrame获取状态栏高度,改用statusBarManager的方式,避免多场景下的兼容性问题。

内容的提问来源于stack exchange,提问作者Augusto Carmo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:59:41