CoreGraphics石英在透明alpha路径上绘制阴影

18 drawing core-graphics objective-c shadow quartz-graphics

在网上搜索大约4个小时没有得到答案:
如何在具有透明度的路径上绘制阴影?

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(c, 2);
    CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] CGColor]);
    CGContextSetShadowWithColor(c, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]);
    CGContextSetFillColorWithColor(c, [[UIColor colorWithWhite:1.0 alpha:0.8] CGColor]);

    // Sample Path
    CGContextMoveToPoint(c, 20.0, 10.0);
    CGContextAddLineToPoint(c, 100.0, 40.0);
    CGContextAddLineToPoint(c, 40.0, 70.0);
    CGContextClosePath(c);

    CGContextDrawPath(c, kCGPathFillStroke);
}
Run Code Online (Sandbox Code Playgroud)

我注意到的第一件事,阴影只在中风附近.但到目前为止,这不是问题.路径/ rect后面的阴影仍然可见,这意味着:阴影颜色会影响路径的填充颜色.填充颜​​色应为白色,而不是灰色.如何解决这个问题?

Dav*_*ist 16

您将必须剪切上下文并绘制两次.

首先,您要创建对路径的引用,因为您必须使用它几次并保存图形上下文,以便您可以回到它.

然后,将图形上下文剪辑为路径外的唯一绘制.这是通过将路径添加到覆盖整个视图的路径来完成的.剪裁完成后,用阴影绘制路径,以便在外面绘制.

接下来,将图形上下文恢复为剪切前的状态,并在没有阴影的情况下再次绘制路径.

它会在橙色背景上看起来像这样(白色背景不是很明显)

描述在橙色背景的图画

执行上述绘图的代码如下:

- (void)drawRect:(CGRect)rect
{
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(c, 2);
    CGContextSetStrokeColorWithColor(c, [[UIColor whiteColor] CGColor]);
    CGContextSetFillColorWithColor(c, [[UIColor colorWithWhite:1.0 alpha:0.5] CGColor]);

    // Sample Path
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 20.0, 10.0);
    CGPathAddLineToPoint(path, NULL, 40.0, 70.0); 
    CGPathAddLineToPoint(path, NULL, 100.0, 40.0);
    CGPathCloseSubpath(path);

    // Save the state so we can undo the shadow and clipping later
    CGContextSaveGState(c);
    { // Only for readability (so we know what are inside the save/restore scope
        CGContextSetShadowWithColor(c, CGSizeMake(0, 5), 5.0, [[UIColor blackColor]CGColor]);
        CGFloat width = CGRectGetWidth(self.frame);
        CGFloat height = CGRectGetHeight(self.frame);

        // Create a mask that covers the entire frame
        CGContextMoveToPoint(c, 0, 0);
        CGContextAddLineToPoint(c, width, 0);
        CGContextAddLineToPoint(c, width, height);
        CGContextAddLineToPoint(c, 0, height);
        CGContextClosePath(c);

        // Add the path (which by even-odd rule will remove it)
        CGContextAddPath(c, path);

        // Clip to that path (drawing will only happen outside our path)
        CGContextClip(c);

        // Now draw the path in the clipped context
        CGContextAddPath(c, path);
        CGContextDrawPath(c, kCGPathFillStroke);
    }
    CGContextRestoreGState(c); // Go back to before the clipping and before the shadow

    // Draw the path without the shadow to get the transparent fill
    CGContextAddPath(c, path);
    CGContextDrawPath(c, kCGPathFillStroke);
}
Run Code Online (Sandbox Code Playgroud)

如果你想让整个阴影变得强烈并且不希望填充颜色的透明度使阴影变弱,那么你可以在第一次填充时使用完全不透明的颜色.它会被剪裁,因此无论如何它都不会在路径中可见.它只会影响阴影.

  • 此示例实际上使用非零绕组编号规则来剪切路径,而不是注释状态的奇偶规则.为了使这个方向与另一个方向的路径一起工作,我不得不使用`CGContextEOClip`来代替.有关[填写路径]的两条规则的更多信息(https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_paths/dq_paths.html#//apple_ref/doc/uid/TP30001066 -z211-TPXREF106)在Quartz 2D编程指南中. (2认同)

ipm*_*mcc 12

根据您的评论请求,这是一个更深入的探索.请考虑以下屏幕截图(StackOverflow为我缩小它 - 它有助于查看它的完整大小.):

5种绘制3种不同背景的不同方式

你在这里看到的是三种不同背景(从左到右)的5种不同的绘制方法(从上到下).(我还将填充alpha从0.8降低到0.5以使效果更容易看到.)三种不同的绘制方法是(从上到下):

  1. 只是中风,而不是填充,带阴影
  2. 您在原始问题中的代码中发布的方式
  3. 笔划和填充,没有应用阴影
  4. 只是影子本身
  5. @DavidRönnqvist在答案中提出的方式.

三种不同的背景应该是自我解释的.

你在原来的问题中说:

我注意到的第一件事,阴影只在中风附近.

这就是我加入第一种绘图方法的原因.这就是它确实看起来当只有行程,没有填充,(因此)仅行程被阴影等.

然后,你说:

但到目前为止,这不是问题.路径/ rect后面的阴影仍然可见,这意味着:阴影颜色会影响路径的填充颜色.填充颜​​色应为白色,而不是灰色.

您的原始代码是下一个版本(#2).你所看到的是,笔划的阴影比填充的阴影更暗.这是因为笔触颜色的alpha是1.0,而填充的a​​lpha小于1.0.在版本#4中可能更容易看到这只是阴影 - 它在笔划边缘的周围更暗.版本#3显示没有阴影的图形.看到你可以看到红色和图像填充形状半遮挡?因此,在原始图形中,您通过对象本身可以看到对象自己的阴影.

如果这没有意义,那就试着想一块有一点色彩的玻璃(如果你是摄影,想一下中性密度滤镜).如果你把这个玻璃放在光源和另一个表面之间,然后从侧面看,只看下面的表面,你知道半透明的玻璃会投下一些阴影,但不会像阴影那样暗影完全不透明(像一块纸板).这就是你所看到的 - 你正在透过物体看它的影子.

版本#5是@DavidRönnqvist的方法.我在评论中谈论的愚蠢效果最容易通过查看图像背景上绘制的形状来欣赏(无论如何).最终看起来像(在版本#5中)是形状是图像的边界,复制的部分,其被覆盖有某种半透明的白色面具.如果你回顾一下版本#3,很明显,在没有阴影的情况下,发生了什么:你正在透过下面图像的半透明形状.然后,如果你看看版本#4,你也可以清楚地知道你的眼睛/相机背后的物体会投射阴影.从那里开始,我会争辩说,在图像版本#2上看到的情况也很明显(即使它在纯色上不太清晰).乍一看,我的眼睛/大脑不知道它在版本#5中看到了什么 - 在我建立"复制,蒙面,部分图像漂浮在原始图像上"的心理模型之前,有一个"视觉不协调"的时刻图片."

因此,如果这种效果(#5)是您的目标,那么David的解决方案将会很有效.我只想指出这是一种非直观的效果.

希望这是有帮助的.我已经把我用过的完整示例项目放在GitHub上生成这个截图.