NSProgressIndicator can't set background color to white
Asked Answered
C

4

8

When I set my progress indicator's background to green, it works as expected.

Code:

loadingIndicator.wantsLayer = true
loadingIndicator.layer?.backgroundColor = NSColor.greenColor().CGColor

Result:

enter image description here

But when I set the background color to white, the background color stays gray (instead of changing to white).

Code:

loadingIndicator.wantsLayer = true
loadingIndicator.layer?.backgroundColor = NSColor.whiteColor().CGColor

Result:

enter image description here

Why does setting the background color to white not work, but green does? How can I correct this issue? I'm on OS X 10.11.4.

EDIT: This apparently only happens when the progress indicator is inside a view that was presented as a popover.

Combings answered 28/4, 2016 at 21:26 Comment(1)
any solution on this, having the same issue with indicator in popoverFantasia
R
5

I had same issue when I use NSProgressIndicator inside NSPopover.

My solution was to set appearance to popover like below.

popover.appearance = NSAppearance(named: NSAppearanceNameAqua)
  • Tried on OSX 10.11.5 / Xcode7.3.1
  • Any other name except for NSAppearanceNameVibrantDark also worked

I'm not sure why this happens, but after setting the property I got correct white background color.

Screenshot: white background progress inside popover

Refutation answered 16/11, 2016 at 15:50 Comment(0)
C
4

I've found a way to fix this. The CALayer of the NSProgressIndicator has a sublayer that is showing the tinted background color you are seeing. Hiding that sublayer will cause no background to ever be shown, and keep the spinner visible.

CALayer *layer = [[self popoverProgressIndicator] layer];
CALayer *backgroundLayer = [[layer sublayers] firstObject];
[backgroundLayer setHidden:YES];

I've only seen this issue when inside of an NSPopover where I was using the solution here to change the background.

Cauda answered 21/10, 2016 at 23:26 Comment(1)
This works for me on macOS Catalina, but only after NSProgressIndicator has been shown. Even viewDidAppear is too early for me.Wetterhorn
J
2

I've encountered this issue recently as well, but mine was related to Dark mode / Light mode in macOS 10.14. It seems to happen when using an NSProgressIndicator inside an NSPopover, as others have mentioned, but also inside a Safari App Extension popover (I think this is because the Safari popover is also an NSPopover that you can't access directly). As horimislime mentioned, messing around with the appearance seems to fix things.

I've created an NSProgressIndicator subclass that, only when the app is running in macOS 10.14 or greater, automatically sets its own appearance to the one the system has, even if this changes while the app is running. The Progress Indicator works for me in previous OS versions, so I left it unchanged if the system is less than 10.14.

Here is the code:

import Cocoa

class TransparentProgressIndicator: NSProgressIndicator {

    override func awakeFromNib() {
        super.awakeFromNib()

        if #available(OSX 10.14, *) {
            // register an observer to detect when the system appearance changes
            UserDefaults.standard.addObserver(self, forKeyPath: "AppleInterfaceStyle", options: .new, context: nil)

            // set the starting appearance to the one the system has
            let light = NSAppearance(named: .aqua)
            let dark = NSAppearance(named: .darkAqua)
            self.appearance = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark" ? dark : light
        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        if #available(OSX 10.14, *) {
            if keyPath == "AppleInterfaceStyle" {

                // set the current appearance to the one the system has
                let val: String? = change?[NSKeyValueChangeKey.newKey] as? String

                if (val == "Dark") {
                    self.appearance = NSAppearance(named: .darkAqua)
                }
                else {
                    self.appearance = NSAppearance(named: .aqua)
                }
            }
        }
    }

    deinit {
        if #available(OSX 10.14, *) {
            UserDefaults.standard.removeObserver(self, forKeyPath: "AppleInterfaceStyle")
        }
    }

}

This way, the progress indicator stays transparent with no weird tinted background and still changes its color scheme according to the system appearance. In order to use this, you need to add the name of this subclass as the "Custom Class" property in interface builder:

Custom Class example

Now, in order to have a custom background color as requested in the question, you can just have a containing NSBox and add a color to that:

Custom NSBox properties ProgressIndicator constraints

Joshia answered 23/10, 2019 at 13:48 Comment(0)
R
1

I had same issue when I use NSProgressIndicator inside NSPopover.

My solution was to set appearance to the NSProgressIndicator like below.

@IBOutlet weak var progressIndicator: NSProgressIndicator!

override func viewDidLoad() {
    super.viewDidLoad()
    self.progressIndicator.appearance = NSAppearance(named: .aqua)
}

If you prefer you can solve the problem even setting the appearence to the whole popover:

popover.appearance = NSAppearance(named: .aqua)
Radiotherapy answered 28/1, 2020 at 12:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.