views:

3389

answers:

3

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

A: 

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 on the line layer like this:

[lineLayer setMask:gradientLayer];

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.

Matt Long
You are right, this would perfectly fit my needs, but unfortunately this is only available with version 3 of the iPhone OS and I want to use at least 2.2. Thanks anyway...
Walchy
A: 

After you draw the line, you can call

CGContextClip(context);

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.

Brad Larson
I tried your suggestion: CGContextSetLineWidth(context, 10.0); // should be thick enough CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 0.0); CGContextMoveToPoint(context, 50,50); CGContextAddLineToPoint(context, 100,100); CGContextStrokePath(context); CGContextClip(context); CGContextDrawLinearGradient (context, myGradient, myStartPoint, myEndPoint, 0);but this throws<Error>: doClip: empty path.The documentation says that CGContextStrokePath(context);clears the path - without this method no error is thrown, but nothing is drawn at all.Any ideas?
Walchy
+1  A: 

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 use CGContextAddRect() instead, which fortunately is what I need. I replaced

CGContextMoveToPoint(context, x, y);
CGContextAddLineToPoint(context, x2, y2);
CGContextStrokePath(context);

with

CGContextSaveGState(context);
CGContextAddRect(context, CGRectMake(x, y, width, height));
CGContextClip(context);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);

and everything works fine. Thanks to Brad Larson for the crucial hint.

Walchy