You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在MacOS应用导航栏添加自定义按钮?参考Xcode导航栏效果

如何在macOS应用中自定义标题栏(添加按钮+调整高度)

我之前也折腾过类似的需求,Xcode那种融合了自定义按钮和加高标题栏的设计确实能提升交互体验,下面分享两种可行的实现方案:

方法一:使用NSTitlebarAccessoryViewController(官方推荐)

这种方式不需要完全替换原生标题栏,而是在标题栏的左侧/右侧插入自定义视图,兼容性更好,也是苹果官方推荐的实现方式:

  1. 创建自定义附件视图控制器
    先写一个继承自NSTitlebarAccessoryViewController的子类,在内部添加你的自定义按钮:
class CustomTitlebarAccessoryVC: NSTitlebarAccessoryViewController {
    override func loadView() {
        // 设置附件视图的高度,对应标题栏要加高的尺寸
        self.view = NSView(frame: NSRect(x: 0, y: 0, width: 220, height: 48))
        self.view.wantsLayer = true
        self.view.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
        
        // 添加自定义按钮并绑定点击事件
        let customBtn = NSButton(title: "自定义操作", target: self, action: #selector(onCustomBtnClick))
        customBtn.frame = NSRect(x: 16, y: 8, width: 120, height: 32)
        self.view.addSubview(customBtn)
    }
    
    @objc private func onCustomBtnClick() {
        print("自定义按钮被触发啦")
    }
}
  1. 将附件控制器挂载到窗口
    在你的窗口控制器(NSWindowController)或者窗口初始化逻辑中,添加这个附件控制器并调整标题栏样式:
class MainWindowController: NSWindowController {
    override func windowDidLoad() {
        super.windowDidLoad()
        
        // 配置标题栏基础样式,让附件视图能正常显示
        window?.titlebarAppearsTransparent = true
        window?.titleVisibility = .hidden
        window?.toolbarStyle = .unifiedCompact
        
        // 创建并添加附件控制器,指定放在标题栏左侧
        let accessoryVC = CustomTitlebarAccessoryVC()
        accessoryVC.layoutAttribute = .leading
        window?.addTitlebarAccessoryViewController(accessoryVC)
        
        // 调整标题栏整体高度,数值为默认高度之上增加的部分
        window?.titlebarHeightAdjustment = 16
    }
}

方法二:完全自定义标题栏(更高自由度)

如果需要像Xcode那样完全掌控标题栏的布局和样式,可以直接隐藏原生标题栏,自己实现一个:

  1. 隐藏原生标题栏
    在窗口初始化时,设置窗口样式以隐藏原生标题栏:
window?.styleMask.insert(.fullSizeContentView)
window?.titlebarAppearsTransparent = true
window?.titleVisibility = .hidden
  1. 实现自定义标题栏视图
    创建一个NSView子类作为自定义标题栏,添加按钮同时保留窗口拖拽功能:
class CustomTitlebarView: NSView {
    override func awakeFromNib() {
        super.awakeFromNib()
        self.wantsLayer = true
        self.layer?.backgroundColor = NSColor.controlBackgroundColor.cgColor
        
        // 添加左侧自定义按钮
        let backBtn = NSButton(title: "返回", target: self, action: #selector(onBackBtnClick))
        backBtn.frame = NSRect(x: 16, y: 8, width: 60, height: 32)
        self.addSubview(backBtn)
        
        // 可以在这里添加更多按钮,比如右侧的功能按钮
    }
    
    // 重写鼠标事件,让自定义标题栏支持窗口拖拽
    override func mouseDown(with event: NSEvent) {
        window?.performDrag(with: event)
    }
    
    @objc private func onBackBtnClick() {
        print("返回按钮被点击")
    }
}
  1. 将自定义标题栏添加到窗口布局
    在窗口的contentView中插入自定义标题栏,并用Auto Layout固定位置:
// 实例化自定义标题栏
let titlebarView = CustomTitlebarView(frame: NSRect(x: 0, y: 0, width: window?.frame.width ?? 0, height: 48))
window?.contentView?.addSubview(titlebarView)

// 设置Auto Layout约束,确保标题栏固定在窗口顶部
titlebarView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
    titlebarView.topAnchor.constraint(equalTo: window!.contentView!.topAnchor),
    titlebarView.leadingAnchor.constraint(equalTo: window!.contentView!.leadingAnchor),
    titlebarView.trailingAnchor.constraint(equalTo: window!.contentView!.trailingAnchor),
    titlebarView.heightAnchor.constraint(equalToConstant: 48)
])

额外提示

  • 如果用方法一,titlebarHeightAdjustment的数值要和附件视图的高度匹配,避免布局错位
  • 完全自定义标题栏时,若需要保留原生的最小化/最大化/关闭按钮,可以用window?.standardWindowButton(.closeButton)获取按钮实例,调整位置后添加到自定义视图中
  • 测试时注意不同macOS版本的兼容性,比如Big Sur之后的标题栏样式有细节变化

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

火山引擎 最新活动