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

iOS11下如何调整大标题UINavigationBar高度以仿Apple Music样式

嘿,我刚好折腾过类似的需求——想用iOS11+原生的大标题导航栏(保留缩放特性),同时在大标题上方加个小文本(比如日期),还得解决自动布局约束冲突的问题。给你几个可行的方案:

方案一:自定义NavigationBar子类,调整内部布局(推荐)

这个方案通过自定义导航栏子类,手动添加日期标签,然后调整系统大标题视图的布局约束,既保留原生缩放特性,又能稳定显示顶部小文本。

步骤1:创建自定义NavigationBar

import UIKit

class CustomLargeTitleNavBar: UINavigationBar {
    // 顶部小文本标签
    private let topLabel = UILabel()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupTopLabel()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupTopLabel()
    }
    
    private func setupTopLabel() {
        topLabel.text = "2024年5月20日"
        topLabel.font = .systemFont(ofSize: 14, weight: .regular)
        topLabel.textColor = .secondaryLabel
        topLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(topLabel)
        
        // 先设置基础约束,后续在layoutSubviews中调整关联
        NSLayoutConstraint.activate([
            topLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            topLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            topLabel.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 8)
        ])
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        // 找到系统的大标题视图(这里通过类名匹配,若担心私有API风险,可通过子视图特征遍历)
        guard let largeTitleView = subviews.first(where: { $0.className == "_UINavigationBarLargeTitleView" }) else {
            return
        }
        
        // 强制关闭大标题视图的自动布局掩码,重新设置约束
        largeTitleView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            // 让大标题视图贴在顶部标签下方
            largeTitleView.topAnchor.constraint(equalTo: topLabel.bottomAnchor, constant: 6),
            largeTitleView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            largeTitleView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            largeTitleView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
        ])
        
        // 更新导航栏的固有高度,确保能容纳顶部标签+大标题
        let totalHeight = topLabel.frame.height + 6 + largeTitleView.frame.height + 16
        intrinsicContentSize = CGSize(width: intrinsicContentSize.width, height: totalHeight)
        setNeedsLayout()
    }
}

步骤2:在ViewController中使用

class DemoViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 设置导航栏为大标题模式
        navigationController?.navigationBar.prefersLargeTitles = true
        navigationItem.title = "我的音乐"
        // 强制始终显示大标题(不滚动隐藏)
        navigationItem.largeTitleDisplayMode = .always
        
        // 替换为自定义导航栏
        if let navController = navigationController {
            navController.navigationBar = CustomLargeTitleNavBar(frame: navController.navigationBar.frame)
        }
    }
}

方案二:修改系统约束优先级(规避私有API风险)

如果担心方案一中的私有类名匹配被拒,可以通过遍历大标题视图的约束,修改其优先级后添加自定义约束:

在自定义NavigationBar的layoutSubviews中替换这部分代码:

override func layoutSubviews() {
    super.layoutSubviews()
    
    // 通过子视图特征找大标题视图(比如包含UILabel的视图)
    guard let largeTitleView = subviews.first(where: {
        $0.subviews.contains(where: { $0 is UILabel }) && $0.frame.height > 40
    }) else { return }
    
    // 找到系统给大标题视图设置的顶部约束,降低其优先级
    largeTitleView.constraints.forEach { constraint in
        if constraint.firstAttribute == .top && constraint.secondItem == self {
            constraint.priority = .defaultHigh // 999,低于系统默认的1000
        }
    }
    
    // 添加顶部标签与大标题的关联约束
    NSLayoutConstraint.activate([
        topLabel.bottomAnchor.constraint(equalTo: largeTitleView.topAnchor, constant: -6)
    ])
    
    // 更新导航栏高度
    let totalHeight = topLabel.frame.height + 6 + largeTitleView.frame.height + 16
    intrinsicContentSize = CGSize(width: intrinsicContentSize.width, height: totalHeight)
    setNeedsLayout()
}

注意事项

  1. 确保导航栏的isTranslucent属性设置正确,若需要不透明效果,记得设置barTintColor并关闭半透明:navigationBar.isTranslucent = false
  2. 若使用UITableView/UICollectionView,记得调整contentInset避免内容被导航栏遮挡
  3. 测试不同设备(尤其是刘海屏)的布局适配,可通过safeAreaLayoutGuide调整约束常数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:13:34