CGContextSetLineWidth of varying width around path
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:
Lower View with Custom View on Top:
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];
CGContextSetLineW开发者_JAVA技巧idth(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:
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.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];
}
It would be a lot simpler to simply fill the same path you're stroking.
精彩评论