反转基于笔划的CALayer掩码(不填充)

亲爱的堆栈溢出社区,

我在iOS(Swift)中有一个关于CAShapeLayer的mask属性的问题。

我试图实现的是一个橡皮擦 ,通过掩盖它来擦除部分图像层。 问题出现了,当我尝试颠倒它。

我发现了一些反转path的好方法,但是这些只在使用填充path时才有用。 我想要做的就是画出一条path,用倒置的方式来掩盖图像。 笔画上的线条宽度应该在30.0左右,看起来像橡皮擦。

我尝试了不同的事情。 我目前的版本是这样的:

  1. 创build一个包含橡皮擦笔划path的CAShapeLayer
  2. 设置图层的fill-color nil
  3. 设置stroke-colorline width
  4. 添加图层作为图像层的蒙版

这工作正常,但它只是使图像的部分可见,在中风 。 我想扭转它。 我想到了一个黑色和白色的面具,但这是行不通的,因为面具是通过alpha通道传递的。

有没有人有一个想法如何解决这个问题?

您可以通过使用透明颜色绘制到不透明的图层来实现此目的。 这可以通过使用另一个混合模式进行绘制来完成。 不幸的是CAShapeLayer不支持这个。 因此,你必须编写你自己的形状图层类:

 @interface ShapeLayer : CALayer @property(nonatomic) CGPathRef path; @property(nonatomic) CGColorRef fillColor; @property(nonatomic) CGColorRef strokeColor; @property(nonatomic) CGFloat lineWidth; @end @implementation ShapeLayer @dynamic path; @dynamic fillColor; @dynamic strokeColor; @dynamic lineWidth; - (void)drawInContext:(CGContextRef)inContext { CGContextSetGrayFillColor(inContext, 0.0, 1.0); CGContextFillRect(inContext, self.bounds); CGContextSetBlendMode(inContext, kCGBlendModeSourceIn); CGContextSetStrokeColorWithColor(inContext, self.strokeColor); CGContextSetFillColorWithColor(inContext, self.fillColor); CGContextSetLineWidth(inContext, self.lineWidth); CGContextAddPath(inContext, self.path); CGContextDrawPath(inContext, kCGPathFillStroke); } @end 

使用透明path创build图层:

 ShapeLayer *theLayer = [ShapeLayer layer]; theLayer.path = ...; theLayer.strokeColor = [UIColor clearColor].CGColor; theLayer.fillColor = [UIColor colorWithWhite:0.8 alpha:0.5]; theLayer.lineWith = 3.0; theLayer.opaque = NO; // Important, otherwise you will get a black rectangle 

我已经使用这个代码在绿色背景前画一个透明的圆:

在这里输入图像说明

编辑:这里是Swift图层的相应代码:

 public class ShapeLayer: CALayer { @NSManaged var path : CGPath? @NSManaged var fillColor : CGColor? @NSManaged var strokeColor : CGColor? @NSManaged var lineWidth : CGFloat override class func defaultValue(forKey inKey: String) -> Any? { return inKey == "lineWidth" ? 1.0 : super.defaultValue(forKey: inKey) } override class func needsDisplay(forKey inKey: String) -> Bool { return inKey == "path" || inKey == "fillColor" || inKey == "strokeColor" || inKey == "lineWidth" || super.needsDisplay(forKey: inKey) } override public func draw(in inContext: CGContext) { inContext.setFillColor(gray: 0.0, alpha: 1.0) inContext.fill(self.bounds) inContext.setBlendMode(.sourceIn) if let strokeColor = self.strokeColor { inContext.setStrokeColor(strokeColor) } if let fillColor = self.fillColor { inContext.setFillColor(fillColor) } inContext.setLineWidth(self.lineWidth) inContext.addPath(self.path!) inContext.drawPath(using: .fillStroke) } } 

注意 :通过使用@NSManaged标记属性,可以通过needsDisplay(forKey inKey:)在Swift中实现needsDisplay(forKey inKey:)needsDisplay(forKey inKey:)中的needsDisplayForKey:来轻松使属性成为animation。 我已经适应了Swift代码。

但即使不需要animation,最好用@NSManaged来标记属性,因为QuartzCore会创build图层的副本,并且也应该复制所有的属性。 Swift中的@dynamic是Objective C中的@dynamic的对应@dynamic ,因为它避免了创build属性实现。 相反, CALayer通过value(forKey:)setValue(_:forKey:)获取和设置属性值。