Reputation: 6080
I want to change my status bar app icon when the user switches from default to dark mode and vice versa (using Swift 3). Here’s what i have so far:
func applicationDidFinishLaunching(_ aNotification: Notification) {
DistributedNotificationCenter.default().addObserver(self, selector: #selector(darkModeChanged(sender:)), name: "AppleInterfaceThemeChangedNotification", object: nil)
}
...
func darkModeChanged(sender: NSNotification) {
print("mode changed")
}
Unfortunately, it’s not working. What am I doing wrong?
Upvotes: 13
Views: 7331
Reputation: 348
So, my little additions as well:
enum InterfaceStyle: String {
case Light
case Dark
case Unspecified
}
extension Notification.Name {
static let AppleInterfaceThemeChangedNotification = Notification.Name("AppleInterfaceThemeChangedNotification")
}
extension NSViewController {
var interfaceStyle: InterfaceStyle {
let type = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") ?? "Unspecified"
return InterfaceStyle(rawValue: type) ?? InterfaceStyle.Unspecified
}
}
and somewhere in a NSViewController:
DistributedNotificationCenter.default.addObserver(forName: .AppleInterfaceThemeChangedNotification,
object: nil, queue: OperationQueue.main) {
[weak weakSelf = self] (notification) in // add an observer for a change in interface style
weakSelf?.setAppearance(toStyle: weakSelf!.interfaceStyle)
}
where setAppearance
reacts on the change of style.
Upvotes: 1
Reputation: 3913
If you simply need to update icon images for dark mode, you can do this without notifications by creating a dynamic image that updates automatically.
From Apple's documentation:
To create an image that draws its content dynamically, use the
init(size:flipped:drawingHandler:)
method to initialize your image with a custom drawing handler block. AppKit calls your handler block whenever the system appearance changes, giving you a chance to redraw the image using the new appearance.
Upvotes: 0
Reputation: 8193
Swift 5, Xcode 10.2.1, macOS 10.14.4
Great stuff. My two cents around @Jeffrey's answer:
extension Notification.Name {
static let AppleInterfaceThemeChangedNotification = Notification.Name("AppleInterfaceThemeChangedNotification")
}
So one could (instead of rawValue
):
func listenToInterfaceChangesNotification() {
DistributedNotificationCenter.default.addObserver(
self,
selector: #selector(interfaceModeChanged),
name: .AppleInterfaceThemeChangedNotification,
object: nil
)
}
Remember the @objc
attribute:
@objc func interfaceModeChanged() {
// Do stuff.
}
Upvotes: 2
Reputation: 566
I'm using this Swift 3 syntax successfully:
DistributedNotificationCenter.default.addObserver(self, selector: #selector(interfaceModeChanged(sender:)), name: NSNotification.Name(rawValue: "AppleInterfaceThemeChangedNotification"), object: nil)
func interfaceModeChanged(sender: NSNotification) {
...
}
Upvotes: 18