反转基于笔划的CALayer蒙版(无填充)

问题描述 投票:10回答:1

亲爱的堆栈溢出社区,

我在iOS(Swift)中与CAShapeLayer的mask属性有关。

我要实现的是一个eraser,它通过掩盖来擦除图像层的一部分。当我尝试将其反转时,问题就来了。

我在反转路径时找到了一些很好的答案,但是这些仅在使用filled路径时有用。我尝试做的是stroke路径,并使用倒置的路径来遮盖图像。笔画上的线宽应大约为30.0,因此它看起来像橡皮擦。

我尝试了不同的事情。我当前的版本如下所示:

  1. 创建一个CAShapeLayer来保存橡皮擦行程的路径
  2. 将图层的fill-color设置为nil
  3. 设置stroke-colorline width
  4. 将图层添加为图像图层的蒙版

这很好,但是仅使图像的部分可见[[在笔画内]。我想做reversed。我想到了黑白蒙版,但这不起作用,因为该蒙版是通过Alpha通道传递的。

有人知道如何解决问题吗?
ios swift calayer mask
1个回答
4
投票
您可以通过将透明颜色绘制到不透明层来实现。这可以通过使用另一种混合模式进行绘制来完成。不幸的是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); if(self.strokeColor) { CGContextSetStrokeColorWithColor(inContext, self.strokeColor); } if(self.fillColor) { CGContextSetFillColorWithColor(inContext, self.fillColor); } CGContextSetLineWidth(inContext, self.lineWidth); CGContextAddPath(inContext, self.path); CGContextDrawPath(inContext, kCGPathFillStroke); } @end

创建具有透明路径的层:

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

我已经使用此代码在绿色背景前面绘制了一个带有透明边框的半透明圆:

enter image description here

Edit:这是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) { if let thePath = path { 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(thePath) inContext.drawPath(using: .fillStroke) } } }

注:通过用@NSManaged标记属性,可以分别通过在Swift中实现needsDisplay(forKey inKey:)或在目标C中实现needsDisplayForKey:轻松地使属性具有动画性。我已经相应地修改了Swift代码。

但是,即使您不需要动画,也最好用@NSManaged标记属性,因为QuartzCore会复制图层,并且还应该复制所有属性。 Swift中的@NSManaged与目标C中的@dynamic是对等的,因为它避免了创建属性实现。相反,CALayer分别使用value(forKey:)setValue(_:forKey:)获取并设置属性值。
© www.soinside.com 2019 - 2024. All rights reserved.