获取大标题导航栏的默认收缩高度和展开高度

Get the default shrunk and expanded height of large title navigation bar

我为导航栏启用了大标题:

navigationController?.navigationBar.prefersLargeTitles = true

这使得导航栏以展开的高度开始,并随着用户向下滚动而缩小。

现在,我想在导航栏内添加一个子视图,它会根据导航栏的高度调整大小。为此,我需要获得 导航栏的最大高度和最小高度,这样我就可以计算出它扩展了多少。

我可以这样获取当前导航栏的高度:

guard let height = navigationController?.navigationBar.frame.height else { return }
print("Navigation height: \(height)")

我在 scrollViewDidScroll 里面调用这个,当我滚动时,似乎展开高度在 96 左右,收缩高度在 44 左右。但是,我不想硬编码值。

iPhone 12

Expanded (96.33) Shrunk (44)

iPhone 8

Expanded (96.5) Shrunk (44)

我也只能在用户实际上下滚动时获取这些值,这在生产环境中不起作用。即使我强迫用户滚动,也为时已晚,因为我需要提前知道两个高度,这样我就可以插入调整大小的子视图。

I want to get these values, but without hardcoding or scrolling

有什么方法可以同时获得缩小和展开的导航栏的高度?

使用以下扩展你可以获得额外的高度

extension UINavigationBar
{
    var largeTitleHeight: CGFloat {
        let maxSize = self.subviews
            .filter { [=10=].frame.origin.y > 0 }
            .max { [=10=].frame.origin.y < .frame.origin.y }
            .map { [=10=].frame.size }
        return maxSize?.height ?? 0
    }
} 

我之前说了你可以通过关注

来增加身高
guard let height = navigationController?.navigationBar.frame.maxY else { return }
print("Navigation height: \(height)")

let window = UIApplication.shared.keyWindow
let topPadding = window?.safeAreaInsets.top

let extendedHeight = height - topPadding

您可以通过从扩展高度中减去差异来缩小高度

guard let difference = navigationController?.navigationBar.lagreTitleHeight else {return}
let shrunkHeight = extendedHeight - difference 

一年后遇到了我自己的问题。另一个答案没有用,所以我使用了视图层次结构。

缩小的样子好像是嵌入了一个叫_UINavigationBarContentView的class。由于这是私有 class,我无法直接访问它。但是,它的 y 起源是 0 并且里面有一个 UILabel。这就是我需要知道的!

extension UINavigationBar {
    func getCompactHeight() -> CGFloat {
        
        /// Loop through the navigation bar's subviews.
        for subview in subviews {
            
            /// Check if the subview is pinned to the top (compact bar) and contains a title label
            if subview.frame.origin.y == 0 && subview.subviews.contains(where: { [=10=] is UILabel }) {
                return subview.bounds.height
            }
        }
        
        return 0
    }
}

用法:

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.title = "Navigation"
    
    if
        let navigationBar = navigationController?.navigationBar,
        let window = UIApplication.shared.keyWindow
    {
        navigationBar.prefersLargeTitles = true /// Enable large titles.
        
        let compactHeight = navigationBar.getCompactHeight() // 44 on iPhone 11
        let statusBarHeight = window.safeAreaInsets.top // 44 on iPhone 11
        let navigationBarHeight = compactHeight + statusBarHeight
        print(navigationBarHeight) // Result: 88.0
    }
}

这个答案的缺点是,如果 Apple 更改了 UINavigationBar 的内部结构,它可能无法工作。不过对我来说已经足够好了。