swiftgradientnsviewcgfloatnscolor

How store a tuple for NSGradient(colorsAndLocations:) in swift


To apply a gradient to a NSView, it seems best to make a class that inherits from NSView and override the draw method that sets a path and draws the gradient.

class GradientView: NSView {

var startColor = NSColor.red
var startPosition: CGFloat = 0
var endColor = NSColor.white
var endPosition: CGFloat = 1
var rotation: CGFloat = 0


override func draw(_ dirtyRect: NSRect) {
    super.draw(dirtyRect)

    let bgGradient = NSGradient(colorsAndLocations: (startColor, startPosition), (endColor, endPosition))
    let path = NSBezierPath.init(rect: self.bounds)
    bgGradient?.draw(in: path, angle: rotation)
}
}

(Let me know if there's a better/easier way...)

It works great, but now I want to send a custom collection of colors & color-stops. Note: *With this above method, I am limited to defining two (the startColor & startPosition and endColor & endPosition) only.

I'd like to use (an array ? of) tuples (containing several colors and their stop values). The API to set a color and location is NSGradient(colorsAndLocations:) and uses the tuple (NSColor, CGFloat).

I can add a parameter like var colorStopArray: [(color: NSColor, stop: CGFloat)] = [] that creates an array of (such) tuples. Also I can append values with: colorStopArray.append((startColor, startPosition)).

But how can I assign this to the API?

I've tried many methods and they all cause errors (eg. tried NSGradient(colorsAndLocations: colorStopArray.flatMap{return ($0.color, $0.stop)}) )

So how can send many custom colors+locations to the above class (or hopefully a better suggestion) to create a custom gradient (which will then be drawn on my NSView)?


Solution

  • Using matt's clues, I replaced the let line (using the more appropriate API init(colors:atLocations:colorSpace:)) :

    let bgGradient = NSGradient(colorsAndLocations: (startColor, startPosition), (endColor, endPosition))
    

    with

    let bgGradient = NSGradient(colors: colorStopArray.map { $0.color }, atLocations: colorStopArray.map { $0.stop }, colorSpace: NSColorSpace.genericRGB)
    

    Now it functions as I desired.