self.myPath=[UIBezierPath bezierPathWithArcCenter:center
radius:200
startAngle:0
Here's an alternative that doesn't require reversing the path at all.
You have a portion of a view you essentially want to "clip out":
Let's say you want the white area to be [UIColor whiteColor]
with 75% alpha. Here's how you do it quickly:
UIView
subclass.This view has two properties:
@property (retain) UIColor *fillColor;
@property (retain) UIBezierPath *punchedOutPath;
You override its -drawRect:
method to do this:
- (void)drawRect:(CGRect)rect {
[[self fillColor] set];
UIRectFill(rect);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
[[self punchedOutPath] fill];
CGContextSetBlendMode(ctx, kCGBlendModeNormal);
}
There's a caveat here: The fillColor
of the view must not include the alpha component. So in your case, you'd want that to just be [UIColor whiteColor]
. You then apply the alpha bit yourself by calling [myView setAlpha:0.75]
.
What's going on here: This is using a blend mode called "Destination Out". Mathematically it's defined as R = D*(1 - Sa)
, but in layman's terms it means "Destination image wherever destination image is opaque but source image is transparent, and transparent elsewhere."
So it's going to use the destination (i.e., what's already in the context) wherever the new stuff is transparent (i.e. outside of the bezier path), and then where the bezier path would be opaque, that stuff is going to become transparent. However, the destination stuff must already be opaque. If it's not opaque, the blending doesn't do what you want. This is why you have to provide an opaque UIColor
and then do any transparency you want with the view directly.
I ran this myself, with these circumstances:
[UIColor greenColor]
backgroundfillColor
is whitepunchedOutPath
is a oval that's inset 10 points from the edges of the view.alpha
of 0.75
With the code above, I get this:
The interior is pure green, and the outside has the semi-transparent overlay.
Update
If your covering is an image, then you'll need to create a new image. But the principle is the same:
UIImage* ImageByPunchingPathOutOfImage(UIImage *image, UIBezierPath *path) {
UIGraphicsBeginImageContextWithOptions([image size], YES, [image scale]);
[image drawAtPoint:CGPointZero];
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeDestinationOut);
[path fill];
UIImage *final = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return final;
}
You would then take the result of this function and put it into a UIImageView
.