I know how to draw a simple line:
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextMoveToPoint(context, x, y);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);
And I know how to do a gradient rectangle, i.g.:
CGColorSpaceRef myColorspace=CGColorSpaceCreateDeviceRGB();
size_t num_locations = 2;
CGFloat locations[2] = { 1.0, 0.0 };
CGFloat components[8] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, num_locations);
CGPoint myStartPoint, myEndPoint;
myStartPoint.x = 0.0;
myStartPoint.y = 0.0;
myEndPoint.x = 0.0;
myEndPoint.y = 10.0;
CGContextDrawLinearGradient (context, myGradient, myStartPoint, myEndPoint, 0);
But how could I draw a line with a gradient, i.g. fading in from black to white (and maybe fading out to black on the other side as well) ?
It is possible to stroke arbitrary paths with a gradient, or any other fill effect, such as a pattern.
As you have found, stroked paths are not rendered with the current gradient. Only filled paths use the gradient (when you turn them in to a clip and then draw the gradient).
However, Core Graphics has an amazingly cool procedure
CGContextReplacePathWithStrokedPath
that will transform the path you intend to stroke in to a path that is equivalent when filled.Behind the scenes,
CGContextReplacePathWithStrokedPath
builds up an edge polygon around your stroke path and switches that for the path you have defined. I'd speculate that the Core Graphics rendering engine probably does this anyway in calls toCGContextStrokePath
.Here's Apple's documentation on this:
So, convert your path in to something you can fill, turn that in to a clip, and then draw your gradient. The effect will be as if you had stroked the path with the gradient.
Code
It'll look something like this…
Further notes
It's worth emphasising part of the documentation above:
The obvious parameter is the line width. However, all line drawing state is used, such as stroke pattern, mitre limit, line joins, caps, dash patterns, etc. This makes the approach extremely powerful.
For additional details see this answer of this S.O. question.
You can use Core Animation layers. You can use a CAShaperLayer for your line by settings its path property and then you can use a CAGradientLayer as a layer mask to your shape layer that will cause the line to fade.
Replace your CGContext... calls with calls to CGPath... calls to create the line path. Set the path field on the layer using that path. Then in your gradient layer, specify the colors you want to use (probably black to white) and then set the mask to be the line layer like this:
What's cool about the gradient layer is that is allows you to specify a list of locations where the gradient will stop, so you can fade in and fade out. It only supports linear gradients, but it sounds like that may fit your needs.
Let me know if you need clarification.
EDIT: Now that I think of it, just create a single CAGradientLayer that is the width/height of the line you desire. Specify the gradient colors (black to white or black to clear color) and the startPoint and endtPoints and it should give you what you need.
its work for me.
After several tries I'm now sure that gradients doesn't affect strokes, so I think it's impossible to draw gradient lines with
CGContextStrokePath()
. For horizontal and vertical lines the solution is to useCGContextAddRect()
instead, which fortunately is what I need. I replacedwith
and everything works fine. Thanks to Brad Larson for the crucial hint.
After you draw the line, you can call
to clip further drawing to your line area. If you draw the gradient, it should now be contained within the line area. Note that you will need to use a clear color for your line if you just want the gradient to show, and not the line underneath it.
There is the possibility that a line will be too thin for your gradient to show up, in which case you can use
CGContextAddRect()
to define a thicker area.I present a more elaborate example of using this context clipping in my answer here.