Search code examples
objective-ciosquartz-2d

CGContextEOFillPath + CGContextDrawLinearGradient


I have succeeded in drawing a rectangle which has a hole inside of the shape of a rounded rectangle using CGContextEOFillPath. I can change the colour of my shape. However, I would like to use a gradient, I suppose that I have got to use CGContextDrawLinearGradient, however, I can't make it work. It keep painting the entire rectangle, hole included.

Here is the code that I am using

- (void)drawRect:(CGRect)rect 
{
[super drawRect:rect];

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGFloat frameWidth = 1; //[CQMFloatingContentOverlayView frameWidth];

CGFloat radius = [self cornerRadius];
CGSize viewSize = [self frame].size;
CGPathRef path = CQMPathCreateRoundingRect(CGRectMake(frameWidth, frameWidth,
                                                      viewSize.width - frameWidth * 2,
                                                      viewSize.height - frameWidth * 2),
                                 radius, radius, radius, radius);
CGContextAddRect(context, CGRectMake(0, 0, viewSize.width, viewSize.height));
CGContextAddPath(context, path);
    CGContextEOFillPath(context);
CGPathRelease(path);
CGContextRestoreGState(context);
}


CGPathRef CQMPathCreateRoundingRect(CGRect rect, CGFloat blRadius, CGFloat brRadius, CGFloat trRadius, CGFloat tlRadius) {
CGPoint tlPoint = rect.origin;
CGPoint brPoint = CGPointMake(rect.origin.x + rect.size.width,
                              rect.origin.y + rect.size.height);
CGMutablePathRef path = CGPathCreateMutable();

CGPathMoveToPoint(path, NULL, tlPoint.x + tlRadius, tlPoint.y);
CGPathAddArcToPoint(path, NULL,
                    brPoint.x, tlPoint.y,
                    brPoint.x, tlPoint.y + trRadius,
                    trRadius);
CGPathAddArcToPoint(path, NULL,
                    brPoint.x, brPoint.y,
                    brPoint.x - brRadius, brPoint.y,
                    brRadius);
CGPathAddArcToPoint(path, NULL,
                    tlPoint.x, brPoint.y,
                    tlPoint.x, brPoint.y - blRadius,
                    blRadius);
CGPathAddArcToPoint(path, NULL,
                    tlPoint.x, tlPoint.y,
                    tlPoint.x + tlRadius, tlPoint.y,
                    tlRadius);
CGPathCloseSubpath(path);

return path;
}

I don't know where to put the gradient code, I have tried before and after the CGContextEOFillPath but could not reach my objective.


Solution

  • This code should make what you want (check for syntax and typos, code is directly written in answer)

    - (void)drawRect:(CGRect)rect {
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
        CGFloat gradientColors[] =
        {        
            0.1, 0.1, 0.5, 1.00,
            0.9, 0.9, 1.0, 1.00,
        };
    
        CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, NULL, sizeof(gradientColors)/(sizeof(gradientColors[0])*4));
    
        CGColorSpaceRelease(colorSpace);
    
        CGContextSaveGState(context);
        CGFloat frameWidth = 1; //[CQMFloatingContentOverlayView frameWidth];
    
        CGFloat radius = [self cornerRadius];
        CGSize viewSize = [self frame].size;
        CGPathRef path = CQMPathCreateRoundingRect(CGRectMake(frameWidth, frameWidth,
                                                          viewSize.width - frameWidth * 2,
                                                          viewSize.height - frameWidth * 2),
                                         radius, radius, radius, radius);
        CGContextAddRect(context, CGRectMake(0, 0, viewSize.width, viewSize.height));
        CGContextAddPath(context, path);
        CGContextEOClip(context);
    
        CGContextDrawLinearGradient(context, gradient, CGPointMake(0, 0),           CGPointMake(viewSize.width, viewSize.height), kCGGradientDrawsBeforeStartLocation);
    
    
    CGPathRelease(path);
        CGContextRestoreGState(context);
    }