Question

I have a gradient that has rounded corners that I an using for a custom UITableViewCell background. I am trying to apply a stroke to the path but cannot quite do it, and can't see where I am going wrong.

  CGFloat minx = CGRectGetMinX(rect) , midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
  CGFloat miny = CGRectGetMinY(rect) , maxy = CGRectGetMaxY(rect) ;
  minx = minx + 1;
  miny = miny ;

  maxx = maxx - 1;
  maxy = maxy - 1;

  CGContextMoveToPoint(c, minx, miny);
  CGContextAddArcToPoint(c, minx, maxy, midx, maxy, kDefaultMargin);
  CGContextAddArcToPoint(c, maxx, maxy, maxx, miny, kDefaultMargin);
  CGContextAddLineToPoint(c, maxx, miny);
  CGContextAddLineToPoint(c, minx, miny);

  // Fill and stroke the path
  CGContextClip(c);
  CGContextStrokePath(c);  

  CGFloat locations[2] = { 0.0, 1.0 };
  CGFloat mycomponents[8] = TABLE_CELL_BACKGROUND;
  CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
  CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace, mycomponents, locations, 2);
  CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);
  CGGradientRelease(myGradient);
  CGColorSpaceRelease(myColorspace);

This code rounds the rectangle right and applies the gradient, but does not stroke the row. Where is my mistake?

alt text http://grab.by/26Ye



EDIT: As per subw's recommendations, I changed the code to be:

    CGContextRef c = UIGraphicsGetCurrentContext();
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef myGradient = nil;
    CGFloat components[8] = TABLE_CELL_BACKGROUND;
    CGContextSetFillColorWithColor(c, [[UIColor redColor] CGColor]);
    CGContextSetStrokeColorWithColor(c, [[UAColor redColor] CGColor]);
    CGContextSetLineWidth(c, 2);

    CGFloat minx = CGRectGetMinX(rect) , midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
    CGFloat miny = CGRectGetMinY(rect) , maxy = CGRectGetMaxY(rect) ;
    minx = minx + 1;
    miny = miny ;

    maxx = maxx - 1;
    maxy = maxy - 1;

    CGContextMoveToPoint(c, minx, miny);
    CGContextAddArcToPoint(c, minx, maxy, midx, maxy, kDefaultMargin);
    CGContextAddArcToPoint(c, maxx, maxy, maxx, miny, kDefaultMargin);
    CGContextAddLineToPoint(c, maxx, miny);
    CGContextAddLineToPoint(c, minx, miny);

    // Fill and stroke the path
    CGContextSaveGState(c);
    CGContextClip(c);

    CGFloat locations[2] = { 0.0, 1.0 };
    CGFloat mycomponents[8] = TABLE_CELL_BACKGROUND;
    CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
    myGradient = CGGradientCreateWithColorComponents(myColorspace, mycomponents, locations, 2);
    CGContextDrawLinearGradient(c, myGradient, CGPointMake(minx,miny), CGPointMake(minx,maxy), 0);

    CGContextRestoreGState(c);
    CGContextStrokePath(c);

But the rect comes out like this…

alt text http://grab.by/2714

...with no border. If I change the CGContextStrokePath(c) to be CGContextStrokeRect(c, rect), the stroke shows up (I made it red for clarification). But somehow, when stroking the path, I am not getting any stroke :(

alt text http://grab.by/27aM

Was it helpful?

Solution

Responding to your revised code, I quote the documentation:

Unlike the current path, the current clipping path is part of the graphics state. Therefore, to re-enlarge the paintable area by restoring the clipping path to a prior state, you must save the graphics state before you clip and restore the graphics state after you’ve completed any clipped drawing.

After determining the new clipping path, the function resets the context’s current path to an empty path.

CGContextClip

So, the current drawing path is not part of the graphics state. So here's what you're doing:

  1. Build drawing path
  2. Save gstate
  3. Add current drawing path to clipping path; clear current drawing path
  4. Draw gradient
  5. Restore gstate (previous clipping path is restored; drawing path remains empty)
  6. Stroke nothing

The solution is to draw the path into a CGPath object, then add it as the current path both before clipping (after saving the gstate) and before stroking.

You should also decide whether you want this to be an outer stroke, an inner stroke, or a centered stroke. For a centered stroke, stroke while not clipped. For an inner stroke, stroke while clipped. For an outer stroke, reverse the path, then clip, then stroke. You'll want to double your line width for both of the last two forms, since you'll be clipping out half of the stroke.

If I change the CGContextStrokePath(c) to be CGContextStrokeRect(c, rect), the stroke shows up.

Because that function adds a path of that rectangle to the current drawing path before stroking.

OTHER TIPS

Not sure, but maybe you're painting the gradient over the stroke?

You're either drawing the gradient over the stroke, and/or clipping the region you stroke.

I think the following might work better:

CGContextSaveGState(c);
CGContextClip(c);

//gradient drawing stuff

CGContextRestoreGState(c);
CGContextStrokePath(c);

Of course, you also have to set the stroke color and width correctly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top