Gradient Progress Bar (NSProgressIndicator)

2.4k Views Asked by At

I am attempting to customize my progress bar (NSProgressIndicator) to load the coloured tint as a gradient. For example:

Estimated Progress Value & Corresponding Colours

  • 0.0 = NSColor.blue
  • 0.5 = NSColor.red
  • 1.0 = NSColor.green

If you're still not sure as to what I'm trying to accomplish, it looks something like this:

https://i0.wp.com/www.cssscript.com/wp-content/uploads/2015/01/iOS-Style-Gradient-Progress-Bar-with-Pure-CSS-CSS3.jpg?zoom=2&fit=427%2C315&ssl=1

There's a good chance that I'm not heading in the right direction, but I thought I'd try. Still new to programming for macOS (haven't covered it in school yet).

ViewController.swift

import Cocoa
import WebKit

class ViewController: NSViewController, WKUIDelegate, WKNavigationDelegate {

    // Main View Elements
    @IBOutlet var webView: WKWebView!
    @IBOutlet var progressBar: NSProgressIndicator!

    override func viewWillAppear() {
        webView.addObserver(self, forKeyPath: "estimatedProgress", options: .new, context: nil)

        let gradient = CAGradientLayer()

        gradient.colors = [NSColor.blue.cgColor,
                           NSColor.red.cgColor,
                           NSColor.green.cgColor]

        gradient.locations = [0, 0.5, 1.0]

        gradient.frame = view.frame

        // view.layer.mask = gradient
        progressBar.layer?.mask = gradient
        progressBar.layer?.compositingFilter = gradient
        progressBar.layer?.borderColor = CGColor.clear
        progressBar.layer?.backgroundColor = CGColor.clear
        progressBar.wantsLayer = true
        progressBar.isBezeled = false
    }

    override func viewWillDisappear() {
        webView.removeObserver(self, forKeyPath: "estimatedProgress")
    }

    // Observer for WebView Loading Progress
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if (keyPath == "estimatedProgress") {
            DispatchQueue.main.async {
                self.setProgress(self.webView.estimatedProgress * 100)
            }
        }
    }

    // Set Progress for ProgressBar
    fileprivate func setProgress(_ value: Double) {
        if value == 100 {
            self.progressBar.isHidden = true
            return
        }

        self.progressBar.isHidden = false
        self.progressBar.doubleValue = value
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.navigationDelegate = self
        let request = URL(string: "https://google.com")!
        webView.load(URLRequest(url: request))
    }

    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        self.setProgress(0)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.setProgress(100)
    }

}

Furthermore, if possible, could you explain why your method works, as well as why mine fails to work. I'm really trying to improve my programming knowledge and skills.

Thank you for reading!

0

There are 0 best solutions below