如何修改两个圆形相交区域的颜色?iOS绘图实现疑问
解决两圆相交区域变色问题
嘿,我来帮你搞定这个需求!你现在已经画出了两个黑色圆形,也尝试用CGRectIntersection拿到了相交的矩形,但其实这个矩形只是两圆外接的重叠矩形,没办法精准表示圆形的相交区域。要实现把两圆重叠部分改成白色的效果,得用Core Graphics的路径组合或者裁剪功能,下面给你两种可行的方案,代码都帮你调整好了:
方案一:直接创建相交路径填充白色
这个方法是先画出两个黑色圆,然后生成两个圆路径的交集,最后给交集填充白色,逻辑很直观:
- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); // 绘制第一个黑色圆形(注意:圆心要用MidX/MidY,不是MinX/MinY,之前的代码这里有小问题) CGRect circle1 = CGRectMake(100, 200, 80, 80); CGContextAddArc(ctx, CGRectGetMidX(circle1), CGRectGetMidY(circle1), CGRectGetWidth(circle1)/2, 0, 2*M_PI, NO); CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor); CGContextFillPath(ctx); // 绘制第二个黑色圆形 CGRect circle2 = CGRectMake(170, 200, 80, 80); CGContextAddArc(ctx, CGRectGetMidX(circle2), CGRectGetMidY(circle2), CGRectGetWidth(circle2)/2, 0, 2*M_PI, NO); CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor); CGContextFillPath(ctx); // 创建第一个圆的路径 CGMutablePathRef circlePath1 = CGPathCreateMutable(); CGPathAddArc(circlePath1, NULL, CGRectGetMidX(circle1), CGRectGetMidY(circle1), CGRectGetWidth(circle1)/2, 0, 2*M_PI, NO); // 创建第二个圆的路径 CGMutablePathRef circlePath2 = CGPathCreateMutable(); CGPathAddArc(circlePath2, NULL, CGRectGetMidX(circle2), CGRectGetMidY(circle2), CGRectGetWidth(circle2)/2, 0, 2*M_PI, NO); // 获取两个路径的交集(就是两圆重叠的区域) CGPathRef intersectionPath = CGPathCreateWithPathByClippingToPath(circlePath1, NULL, circlePath2); // 给交集区域填充白色 CGContextAddPath(ctx, intersectionPath); CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor); CGContextFillPath(ctx); // 释放路径对象,避免内存泄漏 CGPathRelease(circlePath1); CGPathRelease(circlePath2); CGPathRelease(intersectionPath); }
方案二:用裁剪功能实现(更简洁)
这个方法利用Core Graphics的裁剪机制,先把绘制范围限制在第一个圆内,然后在这个范围内绘制第二个圆的白色填充,这样只有重叠部分会被白色覆盖:
- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); // 先绘制两个黑色圆形 CGRect circle1 = CGRectMake(100, 200, 80, 80); CGContextAddArc(ctx, CGRectGetMidX(circle1), CGRectGetMidY(circle1), CGRectGetWidth(circle1)/2, 0, 2*M_PI, NO); CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor); CGContextFillPath(ctx); CGRect circle2 = CGRectMake(170, 200, 80, 80); CGContextAddArc(ctx, CGRectGetMidX(circle2), CGRectGetMidY(circle2), CGRectGetWidth(circle2)/2, 0, 2*M_PI, NO); CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor); CGContextFillPath(ctx); // 保存当前上下文状态,方便后续恢复 CGContextSaveGState(ctx); // 设置裁剪区域为第一个圆的范围 CGContextAddArc(ctx, CGRectGetMidX(circle1), CGRectGetMidY(circle1), CGRectGetWidth(circle1)/2, 0, 2*M_PI, NO); CGContextClip(ctx); // 在裁剪区域内绘制第二个圆的白色填充,只有重叠部分会显示 CGContextAddArc(ctx, CGRectGetMidX(circle2), CGRectGetMidY(circle2), CGRectGetWidth(circle2)/2, 0, 2*M_PI, NO); CGContextSetFillColorWithColor(ctx, [UIColor whiteColor].CGColor); CGContextFillPath(ctx); // 恢复上下文状态,不影响后续绘制操作 CGContextRestoreGState(ctx); }
关键注意点
- 你原来的代码里
CGContextAddArc用了CGRectGetMinX和CGRectGetMinY,这是错误的!因为这个方法的前两个参数是圆心的坐标,应该用CGRectGetMidX和CGRectGetMidY来获取矩形的中心,也就是圆心位置,我已经在代码里修正了这个问题。 - 两种方案都能实现你要的效果,方案二更简洁,不需要额外创建路径对象,性能也更好。
内容的提问来源于stack exchange,提问作者ch.chay




