23

The code below nicely creates a rounded rectangle that is defined by a CGRect (rectRect).

It fills fine, but I am not getting a stroke. Any ideas why I can't see the stroke?

-(void)drawRect:(CGRect)rect {

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextSetRGBFillColor(ctx, 0, 0, 0, 0.4);
    CGContextSetRGBStrokeColor(ctx, 1, 1, 1, 1);
    CGContextSetLineWidth(ctx, 4.0);

    float fw, fh;
    rect = rectRect;
    float ovalWidth = 12;
    float ovalHeight = 12;

    if (ovalWidth == 0 || ovalHeight == 0) {
        CGContextAddRect(ctx, rect);
        return;
    }

    CGContextTranslateCTM (ctx, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM (ctx, ovalWidth, ovalHeight);
    fw = CGRectGetWidth (rect) / ovalWidth;
    fh = CGRectGetHeight (rect) / ovalHeight;
    CGContextMoveToPoint(ctx, fw, fh/2);
    CGContextAddArcToPoint(ctx, fw, fh, fw/2, fh, 1);
    CGContextAddArcToPoint(ctx, 0, fh, 0, fh/2, 1);
    CGContextAddArcToPoint(ctx, 0, 0, fw/2, 0, 1);
    CGContextAddArcToPoint(ctx, fw, 0, fw, fh/2, 1);
    CGContextClosePath(ctx);

    CGContextFillPath(ctx);
    CGContextStrokePath(ctx);

}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
OWolf
  • 5,012
  • 15
  • 58
  • 93

2 Answers2

59

When you paint a path, either by stroking it or by filling it, the graphics context resets its path to empty. So after you call CGContextFillPath, the context doesn't have a path to stroke.

Instead of trying to fill the path and then stroke it, you can use the CGContextDrawPath function to do both in one call:

CGContextDrawPath(ctx, kCGPathFillStroke);

The kCGPathFillStroke constant tells Core Graphics to fill the path and then stroke it.

On the other hand, you could use UIBezierPath and UIColor to reduce the amount of code substantially:

-(void)drawRect:(CGRect)rect {
    [[UIColor colorWithWhite:0 alpha:0.4] setFill];
    [[UIColor whiteColor] setStroke];

    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rectRect cornerRadius:12];
    path.lineWidth = 4;
    [path fill];
    [path stroke];
}
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
8

Swift 5 version. The important part:

override func draw(_ rect: CGRect) {
    guard let context = UIGraphicsGetCurrentContext() else { return }
    context.move(...) // Make path
    context.addLine(...)
    ...
    context.closePath()
    context.setLineWidth(lineWidth)
    context.setStrokeColor(strokeColor!.cgColor)
    context.setFillColor(fillColor!.cgColor)
    context.drawPath(using: .fillStroke) // Fill and stroke
}
Zoltan Vinkler
  • 1,207
  • 1
  • 15
  • 20