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

Mac开发:如何在状态栏中添加ProgressBar作为按钮?

在Mac状态栏添加进度条的实现思路

你说的没错,默认的NSStatusItem按钮确实只能直接设置图片和文字,但其实我们可以通过自定义视图或者给按钮添加子视图的方式,把NSProgressIndicator(进度条)塞进状态栏里,刚好能实现你想要的效果。

我给你分享两种可行的思路,都能搞定这个需求:

思路一:给NSStatusItem的Button直接添加进度条子视图

这种方式最简单,不用替换整个状态栏项的视图,直接在现有按钮上叠加进度条:

let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

if let button = statusItem.button {
    // 先设置你原本的图片和文字
    button.image = NSImage(named: NSImage.Name("JustSomeImage"))
    button.title = "Hello"
    button.action = #selector(togglePopover(_:))
    
    // 创建进度条
    let progressBar = NSProgressIndicator()
    progressBar.style = .bar // 或者用.indeterminate做转圈的加载效果
    progressBar.isIndeterminate = false // 如果是确定进度就设为false
    progressBar.maxValue = 100
    progressBar.doubleValue = 50 // 初始进度50%
    
    // 把进度条添加为按钮的子视图
    button.addSubview(progressBar)
    
    // 用AutoLayout布局,让进度条贴合按钮的底部,左右留一点边距
    progressBar.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        progressBar.leadingAnchor.constraint(equalTo: button.leadingAnchor, constant: 4),
        progressBar.trailingAnchor.constraint(equalTo: button.trailingAnchor, constant: -4),
        progressBar.bottomAnchor.constraint(equalTo: button.bottomAnchor, constant: -2),
        progressBar.heightAnchor.constraint(equalToConstant: 2) // 状态栏高度小,进度条别太高
    ])
    
    // 确保进度条在最上层,不被图片/文字挡住
    progressBar.layer?.zPosition = 1
}

@objc func togglePopover(_ sender: Any?) {
    // 你的popover逻辑
}

思路二:替换NSStatusItem的整个自定义视图

如果需要更复杂的布局(比如进度条和图片、文字的位置需要更灵活的控制),可以直接给statusItem设置一个自定义的NSView,把所有元素都放进去:

let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

// 创建自定义视图
let customStatusView = NSView(frame: NSRect(x: 0, y: 0, width: 120, height: NSStatusBar.system.thickness))

// 添加图片
let statusImage = NSImageView(image: NSImage(named: NSImage.Name("JustSomeImage"))!)
statusImage.frame = NSRect(x: 4, y: 2, width: 16, height: 16)
customStatusView.addSubview(statusImage)

// 添加文字标签
let statusLabel = NSTextField(labelWithString: "Hello")
statusLabel.frame = NSRect(x: 24, y: 0, width: 60, height: NSStatusBar.system.thickness)
statusLabel.alignment = .left
customStatusView.addSubview(statusLabel)

// 添加进度条
let progressBar = NSProgressIndicator()
progressBar.style = .bar
progressBar.isIndeterminate = false
progressBar.maxValue = 100
progressBar.doubleValue = 75
progressBar.frame = NSRect(x: 4, y: 2, width: 112, height: 2)
customStatusView.addSubview(progressBar)

// 给自定义视图添加点击事件(因为替换成自定义view后,原来的button action就失效了)
let clickGesture = NSClickGestureRecognizer(target: self, action: #selector(togglePopover(_:)))
customStatusView.addGestureRecognizer(clickGesture)

// 把自定义视图赋值给statusItem
statusItem.view = customStatusView

@objc func togglePopover(_ sender: Any?) {
    // 你的popover逻辑
}

注意事项

  • 状态栏的高度是固定的(NSStatusBar.system.thickness),所以进度条的高度别设太大,不然会被截断。
  • 如果用.indeterminate样式(转圈加载),记得把isIndeterminate设为true,不用设置进度值。
  • 自定义视图时,要自己处理点击事件,默认的button action会失效,所以需要添加手势识别器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:14:48