views:

1204

answers:

1

I am attempting to implement a custom view. This view should display an image surrounded by a gray, rounded rect border. I can get the image to display fine, as well as the border, however, since the border has rounded corners, I need a way to clear those corners such that they correctly display whatever is behind the view. How can I accomplish this?

It seems like I might be able to use CGContextClearRect, but then wouldn't I have to call this multiple times, reconstructing the area outside of my rounded corner? That sounds overly complicated.

Is there a better way to create this view?

Here is my current code:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Draw the image. This will completely fill the current rect.
    [image drawInRect:self.bounds];

    // Ensure we draw completely within our bounds instead of straddling it.
    CGRect rrect = self.bounds;
    rrect.size.height = rrect.size.height - 1.0;
    rrect.size.width = rrect.size.width - 1.0;
    rrect.origin.x = rrect.origin.x + (1.0 / 2);
    rrect.origin.y = rrect.origin.y + (1.0 / 2);

    CGFloat radius = 5.0;
    CGFloat minx = CGRectGetMinX(rrect);
    CGFloat midx = CGRectGetMidX(rrect);
    CGFloat maxx = CGRectGetMaxX(rrect);
    CGFloat miny = CGRectGetMinY(rrect);
    CGFloat midy = CGRectGetMidY(rrect);
    CGFloat maxy = CGRectGetMaxY(rrect);

    // Draw the rounded rect border.
    CGContextSetRGBStrokeColor(context, 0.6, 0.6, 0.6, 1.0);
    CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.0);
    CGContextSetLineWidth(context, 1.0);
    CGContextMoveToPoint(context, minx, midy);
    CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
    CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
    CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
    CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
    CGContextClosePath(context);
    CGContextDrawPath(context, kCGPathFillStroke);
}
+6  A: 

Add the rounded-rect path to the clipping path before drawing the image.

Peter Hosey
Thanks! So, CGContextClip seems to clear the current drawing path. Does that mean I need to trace the same path twice? Once to clip and then once to draw? Also, I have to save the state of the context before clipping and restore it after drawing the image, correct? Else my path straddles the clip.
Sebastian Celis
You only need the path in the current path if you're going to fill it or stroke it. Drawing an image does not have anything to do with the current path; only the clipping path affects it. And yes, if you want to draw un-clipped after, you must gsave before and grestore after.
Peter Hosey
But you also need the path in the current path if you are going to clip to it (when calling CGContextClip). So I have to add the path to the context twice, right? Once right before CGContextClip and once before stroking. Just making sure that I am not missing any tricks.
Sebastian Celis
Ah, I missed that you are stroking—I thought you were just drawing the image. You can use a CGPath to only plot the path once: Plot the path in the CGPath object, then add the CGPath to the current path, gsave, clip, draw the image, grestore, and stroke.
Peter Hosey
Awesome! Thanks so much.
Sebastian Celis