Question

I have two rectangles (two closed sub cgpaths). Rectangle B is small and is present inside Rectangle A. All edges within it. Is there a direct way to fill color area external to the rectangle B.

CAShapeLayer fillExternalColor something like that? If not a direct way, how to do this programmatically?

A - Purple color B - Yellow color

Drawing A and then drawing B Drawing B and then drawing A

So I tried drawing A and then drawing B. I wanted B to be of clear color (for now I put Yellow) but then I see purple color of A..

I found CGRectIntersection method that gives AnB and CGRectUnion method that gives AuB. Is there a method that gives the rest of the area which is AuB - AnB?

Was it helpful?

Solution

You are using a CAShapeLayer. If your fillColor and your strokeColor are both opaque (alpha 1.0), you can simply set the layer's backgroundColor to fill those pixels that are within the layer's bounds but outside of its stroked and filled path.

My test code:

@implementation ViewController {
    CAShapeLayer *layer;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    layer = [CAShapeLayer layer];
    layer.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 250, 250)].CGPath;
    layer.fillColor = [UIColor yellowColor].CGColor;
    layer.strokeColor = [UIColor whiteColor].CGColor;
    layer.lineWidth = 4;
    layer.backgroundColor = [UIColor purpleColor].CGColor;
    [self.view.layer addSublayer:layer];
}

- (void)viewDidLayoutSubviews {
    layer.frame = self.view.bounds;
}

@end

Result:

screen shot of test app

OTHER TIPS

I wanted to add red border inner rectangle on UIImage with masked outer part.

I came through this page. The following code is using CGContextEOFillPath can be helpful to others like me. (Some of the code is gathered from other pages.)

    -(UIImage ) imageByDrawingBorderRectOnImage:(UIImage )image theRect:(CGRect)theRect
    {
        // begin a graphics context of sufficient size
        UIGraphicsBeginImageContext(image.size);

        // draw original image into the context
        [image drawAtPoint:CGPointZero];

        // get the context for CoreGraphics
        CGContextRef ctx = UIGraphicsGetCurrentContext();

        // set stroking color and to draw rect
        [[UIColor redColor] setStroke];

        // drawing with a red stroke color
        CGContextSetRGBStrokeColor(ctx, 1.0, 0.0, 0.0, 1.0);

        // the line width to 3
        CGContextSetLineWidth(ctx, 3.0);

        // Add Stroke Rectangle,
        CGContextStrokeRect(ctx, theRect);

        // Now draw fill outside part with partial alpha gray color
        // drawing with a gray stroke color
        CGMutablePathRef aPath = CGPathCreateMutable();
        // outer rectangle
        CGRect rectangle = CGRectMake( 0, 0, image.size.width, image.size.height);
        CGPathAddRect(aPath, nil, rectangle);
        // innter rectangle
        CGPathAddRect(aPath, nil, theRect);
        // set gray transparent color
        CGContextSetFillColorWithColor(ctx, [UIColor colorWithRed:0.75 green:0.75 blue:0.75 alpha:0.5].CGColor);
        // add the path to Context
        CGContextAddPath(ctx, aPath);
        // This method uses Even-Odd Method to draw in outer rectangle
        CGContextEOFillPath(ctx);

        // make image out of bitmap context
        UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();

        // free the context
        UIGraphicsEndImageContext();

        return retImage;
    }

Regards.

Assuming A is the bigger shape, B is the smaller, inner shape, and bounds refers to the containing rect of A (probably the bounds of the view)

  1. Clip shape B to the context (-addClip should do it)
  2. CGContextClearRect the bounds
  3. Fill shape A

Edit, found the source of this code

Given HoleView : UIView you must set:

self.opaque = NO;
self.backgroudColor = [UIColor clearColor];

and in drawRect:

[[UIColor purpleColor] setFill];
UIRectFill(A);

CGRect gapRectIntersection = CGRectIntersection(B, A);    
[[UIColor clearColor] setFill];
UIRectFill(gapRectIntersection);

kCAFillRuleEvenOdd

Specifies the even-odd winding rule. Count the total number of path crossings. If the number of crossings is even, the point is outside the path. If the number of crossings is odd, the point is inside the path and the region containing it should be filled.

Available in OS X v10.6 and later.

Declared in CAShapeLayer.h.

Refer to :CAShapeLayer Class reference

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top