简体   繁体   中英

CGContext clips more than it should

I have a UIView that has 3 custom subviews whose class is called (for now) LVStemp and that represent nodes in a tree. An LVStemp 's frame is larger than the node itself because it will also include some drawing that lies outside the node (not coded yet). LVStemp has a property called nodeFrame that represents the frame of the node itself, in the main view's coordinates.

I'm trying to draw the nodes and fill them with a gradient. But the gradient is clipping in a way that is not what I intend. The result looks like this:

在此处输入图片说明

The top node is filled correctly but the bottom two are not.

Setting up, in the UIView 's superview:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 350, 350)];
    [self.view addSubview:myView];

    LVStemp *node1 = [[LVStemp alloc] init];
    node1.frame = CGRectMake(75, 0, 50, 50);
    node1.nodeFrame = node1.frame;
    node1.backgroundColor = [UIColor clearColor];
    [myView addSubview:node1];

    LVStemp *node2 = [[LVStemp alloc] init];
    node2.frame = CGRectMake(0, 25, 100, 175);
    node2.nodeFrame = CGRectMake(0, 150, 50, 50);
    node2.backgroundColor = [UIColor clearColor];
    [myView addSubview:node2];

    LVStemp *node3 = [[LVStemp alloc] init];
    node3.frame = CGRectMake(100, 25, 100, 175);
    node3.nodeFrame = CGRectMake(150, 150, 50, 50);
    node3.backgroundColor = [UIColor clearColor];
    [myView addSubview:node3];
}

My code in LVStemp.h :

@interface LVStemp : UIView

@property (nonatomic) CGRect nodeFrame; 

@end

My code in LVStemp.m :

@implementation LVStemp

- (void)drawRect:(CGRect)rect
{
    // Build nodeBounds (= nodeFrame converted to self's coordinate system)
    CGRect nodeBounds = [self convertRect:self.nodeFrame fromView:self.superview];

    // Get CGContextRef
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Draw node with gradient
    [self drawEllipseInRect:nodeBounds withGradient:context];
}

- (void)drawEllipseInRect:(CGRect)rect withGradient:(CGContextRef)context
{
    UIGraphicsPushContext(context);
    CGFloat colors[] = {
        0.1, 0.8, 1.0, 1.0,
        0.1, 0.4, 0.9, 1.0
    };

    CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB();
    CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 2);
    CGColorSpaceRelease(baseSpace), baseSpace = NULL;

    CGContextSaveGState(context);
    CGContextAddEllipseInRect(context, rect);
    CGContextClip(context);

    CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxX(rect));

    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
    CGGradientRelease(gradient), gradient = NULL;

    CGContextRestoreGState(context);

    CGContextAddEllipseInRect(context, rect);
    CGContextDrawPath(context, kCGPathStroke);
    UIGraphicsPopContext();
}

@end

( drawEllipseInRect:withGradient: is adapted from here .)

And here's what happens if I comment out the clipping part:

    //CGContextAddEllipseInRect(context, rect);
    //CGContextClip(context);

在此处输入图片说明

Any suggestions?

The context is clipped correct, but you are drawing the gradient at the wrong Position:

CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxX(rect));

Change that to use maxY:

CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));

But as you might have noticed, the strokes are being clipped. That's because they are drawn centered on the given outline. You might consider calling it with some inset:

[self drawEllipseInRect:CGRectInset(nodeBounds, lineWidth/2, lineWidth/2) withGradient:context];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM