On OSX, how do I gradient fill a path stroke?
Asked Answered
L

3

16

Using the plethora of drawing functions in Cocoa or Quartz it's rather easy to draw paths, and fill them using a gradient. I can't seem to find an acceptable way however, to 'stroke'-draw a path with a line width of a few pixels and fill this stroke using a gradient. How is this done?

Edit: Apparently the question wasn't clear enough. Thanks for the responses so far, but I already figured that out. What I want to do is this:

squares
(source: emle.nl)

The left square is NSGradient drawn in a path followed by a path stroke message. The right is what I want to do; I want to fill the stroke using the gradient.

Likelihood answered 29/4, 2010 at 14:8 Comment(1)
The link no longer worksSpearman
S
22

If you convert the NSBezierPath to a CGPath, you can use the CGContextReplacePathWithStrokedPath() method to retrieve a path that is the outline of the stroked path. Graham Cox's excellent GCDrawKit has a -strokedPath category method on NSBezierPath that will do this for you without needing to drop down to Core Graphics.

Once you have the outlined path, you can fill that path with an NSGradient.

Scanty answered 5/5, 2010 at 1:25 Comment(2)
Wonderful! Thank you :) Thanks for the link to drawkit too, it looks very nice.Likelihood
I had problems making this work- my gradient filled the entire clipped area, rather than the path (perhaps this had to do with doing clipping as well). I ended up drawing one shape that was simply the outline of the border, clipping to that path, and then using the gradient fill, and that worked best.Isogamete
E
14

I can't seem to find an acceptable way however, to 'stroke'-draw a path with a line width of a few pixels and fill this stroke using a gradient. How is this done?

[Original answer replaced with the following]

Ah, I see. You want to apply the gradient to the stroke.

To do that, you use a blend mode. I explained how to do this in an answer on another question. Here's the list of steps, adapted to your goal:

  1. Begin a transparency layer.
  2. Stroke the path with any non-transparent color.
  3. Set the blend mode to source in.
  4. Draw the gradient.
  5. End the transparency layer.
Effluent answered 29/4, 2010 at 16:50 Comment(2)
Thanks for the reply. It's however, not what I try to achieve. I've clarified the question a bit.Likelihood
Emiel: Ah, I see. I've replaced the previous contents of my answer with a new answer.Effluent
J
9

According to Peter Hosey's answer I've managed to do a simple gradient curve, which looks like this:

Gradient Curve Image

I've done this in drawRect(_:) method of UIView class by writing the code below:

override func drawRect(rect: CGRect) {
    let context = UIGraphicsGetCurrentContext()

    CGContextBeginTransparencyLayer (context, nil)
    let path = createCurvePath()
    UIColor.blueColor().setStroke()
    path.stroke()
    CGContextSetBlendMode(context, .SourceIn)

    let colors          = [UIColor.blueColor().CGColor, UIColor.redColor().CGColor]
    let colorSpace      = CGColorSpaceCreateDeviceRGB()
    let colorLocations  :[CGFloat] = [0.0, 1.0]
    let gradient        = CGGradientCreateWithColors(colorSpace, colors, colorLocations)
    let startPoint      = CGPoint(x: 0.0, y: rect.size.height / 2)
    let endPoint        = CGPoint(x: rect.size.width, y: rect.size.height / 2)

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, CGGradientDrawingOptions.DrawsBeforeStartLocation)
    CGContextEndTransparencyLayer(context)
}

Function createCurvePath() returns an UIBezierPath object. I've also set path.lineWidth to 5 points.

Jacy answered 21/5, 2016 at 9:33 Comment(1)
Do you know if it's possible to make the path be blue in the beginning and red in the end, but f.e. bend the curve back to where it started?Negligent

© 2022 - 2024 — McMap. All rights reserved.