You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何修改两个圆形相交区域的颜色?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用了CGRectGetMinXCGRectGetMinY,这是错误的!因为这个方法的前两个参数是圆心的坐标,应该用CGRectGetMidXCGRectGetMidY来获取矩形的中心,也就是圆心位置,我已经在代码里修正了这个问题。
  • 两种方案都能实现你要的效果,方案二更简洁,不需要额外创建路径对象,性能也更好。

内容的提问来源于stack exchange,提问作者ch.chay

火山引擎 最新活动