macOS状态栏图标与文本布局优化及动态文本更新问题求助
解决macOS状态栏文本动态更新的问题
我来帮你搞定这个动态更新状态栏文本的需求!你的核心问题是只在初始化时读取了一次percentualDownload的值,没有监听它的变化,所以当UserPreferences里的这个属性更新时,状态栏文本不会同步刷新。下面是具体的修复方案:
问题分析
原代码中,你在StatusBarController的init方法里只设置了一次statusItem.button?.title,而UserPreferences里的percentualDownload是用@Published标记的可观察属性,需要通过订阅它的变化来实时更新UI。另外,你原代码里判断inDownload的逻辑也有问题(错误地访问了$inDownload这个Publisher,而不是实际的属性值)。
修复后的代码
修改StatusBarController
import AppKit import SwiftUI import Combine // 别忘了导入Combine框架 class StatusBarController { @ObservedObject var userPreferences = UserPreferences.instance private var statusBar: NSStatusBar private var statusItem: NSStatusItem private var popover: NSPopover // 添加这个集合来保存订阅,防止被提前释放 private var cancellables = Set<AnyCancellable>() init(_ popover: NSPopover) { self.popover = popover statusBar = NSStatusBar.init() statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let statusBarButton = statusItem.button { // 初始化时先设置一次初始值 updateStatusBarTitle() statusBarButton.image = #imageLiteral(resourceName: "Weather") statusBarButton.image?.size = NSSize(width: 18.0, height: 18.0) statusBarButton.image?.isTemplate = true statusBarButton.action = #selector(togglePopover(sender:)) statusBarButton.target = self statusBarButton.imagePosition = NSControl.ImagePosition.imageLeft } // 订阅percentualDownload的变化,实时更新标题 userPreferences.$percentualDownload .receive(on: DispatchQueue.main) // 确保在主线程更新UI .sink { [weak self] _ in self?.updateStatusBarTitle() } .store(in: &cancellables) // 如果需要监听inDownload的变化,也可以添加订阅 userPreferences.$inDownload .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.updateStatusBarTitle() } .store(in: &cancellables) } // 提取单独的方法来更新标题,避免重复代码 private func updateStatusBarTitle() { if userPreferences.inDownload { statusItem.button?.title = userPreferences.percentualDownload } else { // 这里可以设置下载完成后的文本,比如"完成"或者空字符串 statusItem.button?.title = "完成" } } @objc func togglePopover(sender: AnyObject) { if(popover.isShown) { hidePopover(sender) } else { showPopover(sender) } } func showPopover(_ sender: AnyObject) { if let statusBarButton = statusItem.button { popover.show(relativeTo: statusBarButton.bounds, of: statusBarButton, preferredEdge: NSRectEdge.maxY) } } func hidePopover(_ sender: AnyObject) { popover.performClose(sender) } }
关键改动说明
- 导入Combine框架:因为我们要使用
@Published的订阅功能,必须导入Combine。 - 添加
cancellables集合:用来保存订阅对象,防止订阅被Swift的ARC机制提前释放。 - 提取
updateStatusBarTitle方法:把设置标题的逻辑单独抽出来,避免在初始化和订阅回调里重复写代码,也方便后续维护。 - 订阅属性变化:通过
userPreferences.$percentualDownload.sink()来监听属性的每一次变化,并且切换到主线程更新UI(因为UI操作必须在主线程执行)。 - 修正
inDownload的判断逻辑:直接访问userPreferences.inDownload属性,而不是它的Publisher对象$inDownload。
这样修改后,每当UserPreferences里的percentualDownload或者inDownload发生变化时,状态栏的文本都会自动同步更新啦!
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

