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)?
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.