Search code examples
objective-ciospolygonquartz-2ddrawrect

UIView drawRect() : fill everything except polygon


I need to fill my UIView in drawRect() method with 'reverted polygon' - everything in view is filled with some color except polygon itself.

I've got this code to draw a simple polygon:

CGContextBeginPath(context);
for(int i = 0; i < corners.count; ++i)  
{
    CGPoint cur = [self cornerAt:i], next = [self cornerAt:(i + 1) % corners.count];
    if(i == 0)
        CGContextMoveToPoint(context, cur.x, cur.y);
    CGContextAddLineToPoint(context, next.x, next.y);
}
CGContextClosePath(context);
CGContextFillPath(context);

I found a similar question, but in C#, not Obj-C : c# fill everything but GraphicsPath


Solution

  • Probably the fastest way is to set a clip:

    // create your path as posted
    // but don't fill it (remove the last line)
    
    CGContextAddRect(context, self.bounds);
    CGContextEOClip(context);
    
    CGContextSetRGBFillColor(context, 1, 1, 0, 1);
    CGContextFillRect(context, self.bounds);
    

    Both the other answers suggest to first fill a rect, then draw the shape with clear color on top. Both omit the necessary blend mode. Here's a working version:

    CGContextSetRGBFillColor(context, 1, 1, 0, 1);
    CGContextFillRect(context, self.bounds);
    
    CGContextSetBlendMode(context, kCGBlendModeClear);
    
    // create and fill your path as posted
    

    Edit: Both approaches require the backgroundColor to be the clearColor and opaque to be set to NO.

    Second Edit: The original question was about Core Graphics. Of course there are other ways of masking part of a view. Most notably CALayer's mask property.

    You can set this property to an instance of a CAPathLayer that contains your clip path to create a stencil effect.