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
相关产品推荐
相关产品推荐

