Macos 切换暗模式时,NSAppearance未更新

Macos 切换暗模式时,NSAppearance未更新,macos,macos-big-sur,nsstatusbar,macos-darkmode,Macos,Macos Big Sur,Nsstatusbar,Macos Darkmode,我有一个仅在macOS状态栏中运行的macOS应用程序。我将Info.plist中的“Application is agent(UIElement)”属性更改为“YES”: LSUIElement 我有一个计时器,每5秒打印一次外观名称,如下所示: Timer.scheduledTimer(withTimeInterval:5,repeats:true){in 让外观=NSAppearance.currentDrawing() 打印(外观.名称) } 问题 在“系统设置”中切换“暗/亮”模式

我有一个仅在macOS状态栏中运行的macOS应用程序。我将Info.plist中的“Application is agent(UIElement)”属性更改为“YES”:

LSUIElement
我有一个计时器,每5秒打印一次外观名称,如下所示:

Timer.scheduledTimer(withTimeInterval:5,repeats:true){in
让外观=NSAppearance.currentDrawing()
打印(外观.名称)
}
问题 在“系统设置”中切换“暗/亮”模式时,名称实际上不会更改。它总是打印应用程序启动时设置的外观名称

有没有办法监听系统外观的变化

目标 我的最终目标实际上是将
nsattributed字符串
绘制到
NSImage
,并将该
NSImage
用作
NSStatusItem
按钮的图像

let image:NSImage=//生成图像
statusItem.button?.image=图像
对于属性字符串中的文本,我使用
UIColor.labelColor
,它应该基于系统外观。然而,它似乎不尊重系统外观的变化

当我在暗模式下启动应用程序,然后切换到亮模式时:

当我在亮模式下启动应用程序,然后切换到暗模式时:

旁注
我之所以将
NSAttributedString
转换为
NSImage
,并且不直接在
NSStatusItem
按钮的
attributedTitle
上使用
NSAttributedString
,是因为。

绘制
NSAttributedString
的问题是,
NSAttributedString
不知道如何渲染动态颜色,例如
NSColor.labelColor
。因此,它不会对外观变化做出反应。您必须使用UI元素

解决方案 我通过将
nsattributed字符串
传递给
NSTextField
并将其绘制到
NSImage
中解决了这个问题。很好用

func updateStatusItemImage(){
//使用UI元素:`NSTextField`
让attributedString:NSAttributedString=。。。
设textField=NSTextField(labelWithAttributedString:attributedString)
textField.sizeToFit()
//将'NSTextField'绘制为'NSImage'`
let size=textField.frame.size
让图像=NSImage(大小:大小)
image.lockFocus()
textField.draw(textField.bounds)
image.unlockFocus()
//将绘制的图像指定给“NSStatusItem”的按钮`
statusItem.button?.image=图像
}
对外观变化作出反应 此外,由于
NSImage
不知道
NSAppearance
我需要通过观察
NSStatusItem
按钮的
effectiveAppearance
属性来触发外观更改的重绘:

observation=statusItem.observation(\.button?.effectiveAppearance,选项:[]){[weak self]\uuu,\uu在
//重画
self?.updateStatusItemImage()
}

绘制
NSAttributedString
的问题是,
NSAttributedString
不知道如何渲染动态颜色,例如
NSColor.labelColor
。因此,它不会对外观变化做出反应。您必须使用UI元素

解决方案 我通过将
nsattributed字符串
传递给
NSTextField
并将其绘制到
NSImage
中解决了这个问题。很好用

func updateStatusItemImage(){
//使用UI元素:`NSTextField`
让attributedString:NSAttributedString=。。。
设textField=NSTextField(labelWithAttributedString:attributedString)
textField.sizeToFit()
//将'NSTextField'绘制为'NSImage'`
let size=textField.frame.size
让图像=NSImage(大小:大小)
image.lockFocus()
textField.draw(textField.bounds)
image.unlockFocus()
//将绘制的图像指定给“NSStatusItem”的按钮`
statusItem.button?.image=图像
}
对外观变化作出反应 此外,由于
NSImage
不知道
NSAppearance
我需要通过观察
NSStatusItem
按钮的
effectiveAppearance
属性来触发外观更改的重绘:

observation=statusItem.observation(\.button?.effectiveAppearance,选项:[]){[weak self]\uuu,\uu在
//重画
self?.updateStatusItemImage()
}