views:

21

answers:

1

In one of my apps, I have a custom drawn semitransparent UIView that I use as a cover on top of another UIView for a special effect.

Lower View: alt text

Lower View with Custom View on Top: alt text

It works, its great on the iPhone where the side margins are only 10 pixels, but now I need to expand the left and right margins to match the row below it.

Here is my code:

- (void)draw:(TTStyleContext*)context {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSaveGState(ctx);

    [_color setStroke];
    CGContextSetLineWidth(ctx, MIN(_xwidth, _ywidth));

    CGFloat fw = context.frame.size.width;
    CGFloat fh = context.frame.size.height;

    CGContextMoveToPoint(ctx, fw, floor(fh/2));
    CGContextAddArcToPoint(ctx, fw, fh, floor(fw/2), fh, RD(_radius));
    CGContextAddArcToPoint(ctx, 0, fh, 0, floor(fh/2), RD(_radius));
    CGContextAddArcToPoint(ctx, 0, 0, floor(fw/2), 0, RD(_radius));
    CGContextAddArcToPoint(ctx, fw, 0, fw, floor(fh/2), RD(_radius));
    CGContextClosePath(ctx);
    CGContextStrokePath(ctx);

    CGContextRestoreGState(ctx);

    context.frame = CGRectInset(context.frame, _xwidth/2, _ywidth/2);
    return [self.next draw:context];
}

After setting the _xwidth and _ywidth, the key part of this code is the MIN for the stroke width. The idea here is that the frame is by default, the same stroke width all around. What I am asking it to do is make the stroke width bigger on the sides than on the top and bottom. Using MIN ensures that the stroke does not get the thicker _xwidth size and bleed into the center. If I use the _ywidth value, the sides look great but I don't get the transparent red anymore because the top and bottom borders bleed into the center. This brings me to my question:

Is there a way for me to specify that I want the stroke to be _xwidth thick on the sides and _ywidth thick on the top and bottom? If not, is there another easier way I am overlooking?

With my code, _xwidth set to 42, _ywidth set to 10, I get this: alt text You can see what I am going for here, and how I need to get the side stroke to cover up the uncovered red background.

A: 

I was able to hack it by altering the path and stroking it with the thiner line, then applying another stroke around an expanded rect with the thicker line to mask the overflow

- (void)draw:(TTStyleContext*)context {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSaveGState(ctx);

    CGRect oldFrame = context.frame;

    context.frame = CGRectInset(context.frame, (_xwidth > _ywidth ? _xwidth/2 : 0), (_ywidth > _xwidth ? _ywidth/2 : 0));
    CGFloat ox = (_xwidth > _ywidth ? _xwidth/2 - _ywidth/2 : 0);
    CGFloat oy = (_ywidth > _xwidth ? _ywidth/2 - _xwidth/2 : 0);
    CGFloat fw = context.frame.size.width + ox + (_xwidth > _ywidth ? _ywidth : 0);
    CGFloat fh = context.frame.size.height + oy + (_ywidth > _xwidth ? _xwidth : 0);

    CGContextMoveToPoint(ctx, fw, floor(fh/2));
    CGContextAddArcToPoint(ctx, fw, fh, floor(fw/2), fh, RD(_radius));
    CGContextAddArcToPoint(ctx, ox, fh, ox, floor(fh/2), RD(_radius));
    CGContextAddArcToPoint(ctx, ox, oy, floor(fw/2), oy, RD(_radius));
    CGContextAddArcToPoint(ctx, fw, oy, fw, floor(fh/2), RD(_radius));
    CGContextClosePath(ctx);

    [_color setStroke];
    CGContextSetLineWidth(ctx, MIN(_xwidth, _ywidth));
    CGContextStrokePath(ctx);

    if (_xwidth != _ywidth) {
        CGContextSetLineWidth(ctx, MAX(_xwidth, _ywidth));
        CGContextStrokeRect(ctx, CGRectInset(oldFrame, (_ywidth > _xwidth ? -2*_xwidth : 0), (_xwidth > _ywidth ? -2*_ywidth : 0)));
    }

    CGContextRestoreGState(ctx);

    context.frame = CGRectInset(oldFrame, _xwidth/2, _ywidth/2);
    return [self.next draw:context];
}

alt text

coneybeare