Remove pale-effect on NSStatusBarButton

234 Views Asked by At

I'm looking for a way to remove the pale effect from the NSStatusBarButton. This is a picture of how it currently looks:

NSStatusBarButton with pale image

This is how it should look:

NSStatusBarButton with original image

After looking at Apple's documentation, I found a solution to the problem. If you set the appearance of the button directly (e.g. Aqua or DarkAqua), the pale effect disappears:

if let button = statusBarItem.button {
    ...
    button.appearance = NSAppearance.current // or aqua / darkAqua
}

But the problem is when the user changes the interface theme (e.g. from dark mode to light mode), the NSStatusBarButton does not change its appearance automatically:

NSStatusBarButton does not change the appearance automatically

I could monitor AppleInterfaceThemeChangedNotification and then change the appearance, but that's not a clean solution and I'm not happy with it.

Is there an elegant solution to this? The image in the NSStatusBarButton should simply be displayed without changes (e.g. pale). Because I offer all flags of the world, I only have the images in png format, no PDF images.

2

There are 2 best solutions below

3
vadian On

Write an extension of NSStatusBarButton and override viewDidChangeEffectiveAppearance.

In the body of the method change the appearance explicitly

extension NSStatusBarButton { 
    @available(macOS 10.14, *)
    override public func viewDidChangeEffectiveAppearance() {
        print("viewDidChangeEffectiveAppearance")
        self.appearance = .current 
    }
}
0
Suboptimierer On

Since the solution of vadian, unfortunately, did not work for me, I would like to show my alternative solution here. Maybe it helps somebody else.

Create the NSStatusItem and customize NSStatusBarButton:

...
if let button = statusBarItem.button {
    ...
    button.appearance = NSAppearance.current // removes the pale effect
}
...

Write an extension for Notification.Name to react on AppleInterfaceThemeChangedNotification:

extension Notification.Name {
    static let AppleInterfaceThemeChangedNotification = Notification.Name("AppleInterfaceThemeChangedNotification")
}

Add an Observer to the new notification name:

DistributedNotificationCenter.default.addObserver(self, selector: #selector(interfaceChanged), name: .AppleInterfaceThemeChangedNotification, object: nil)

Respond to the change between light/dark mode:

@objc private static func interfaceChanged() {
    // change button.appearance
}

Make sure that button.appearance is only changed if the necessary macOS version is available:

guard #available(OSX 10.14, *) else {
    return
}

I am sure that there is a cleaner solution. If anyone has an idea, please tell me.