我正在为iPad应用实现一个绘图功能。我使用UIBezierPaths在CAShapeLayers上进行绘制。通过为每个TouchesBegan事件创建一个新的CAShapeLayer,我正在构建一个堆叠的CAShapeLayer数组,以便通过弹出和推送图层到数组中轻松实现撤消和重做。我还使用一些CAShapeLayer.compositingFilters进行一些有趣的图层混合技术。这一切都非常顺利。我的挑战是擦除。
我试图创建第二个CAShapeLayers数组并使用它们来遮罩第一组。当使用不透明颜色进行绘制时,我能够将其添加到遮罩组中,但我无法从遮罩组中删除不透明区域。
我认为我应该能够从一个不透明的基础层开始使用遮罩技术(黑色、白色或其他颜色)。然后,我希望使用UIColor.clear.cgColor绘制UIBezierPaths,并将我的绘制清晰路径与底层的不透明基础遮罩组合或合成。这实际上应该“擦除”遮罩的那个区域,并隐藏我绘制的堆叠的CAShapeLayers。我不想将遮罩层合并成图像,因为这样我将失去通过弹出和推送遮罩数组轻松撤消和重做的能力。
我在下面包含了一些伪代码。任何指针、帮助或解决方案策略将不胜感激!我已经为此工作了几个星期,但还是束手无策。我找不到任何关于我正在努力实现的策略的信息。另外,如果我从一开始就错误地进行绘图功能,并且有一种更容易的方法来绘图,同时保持简单的撤消/重做,并添加擦除,请告诉我。我完全可以调整我的方法!提前感谢您的任何帮助。
我试图创建第二个CAShapeLayers数组并使用它们来遮罩第一组。当使用不透明颜色进行绘制时,我能够将其添加到遮罩组中,但我无法从遮罩组中删除不透明区域。
我认为我应该能够从一个不透明的基础层开始使用遮罩技术(黑色、白色或其他颜色)。然后,我希望使用UIColor.clear.cgColor绘制UIBezierPaths,并将我的绘制清晰路径与底层的不透明基础遮罩组合或合成。这实际上应该“擦除”遮罩的那个区域,并隐藏我绘制的堆叠的CAShapeLayers。我不想将遮罩层合并成图像,因为这样我将失去通过弹出和推送遮罩数组轻松撤消和重做的能力。
我在下面包含了一些伪代码。任何指针、帮助或解决方案策略将不胜感激!我已经为此工作了几个星期,但还是束手无策。我找不到任何关于我正在努力实现的策略的信息。另外,如果我从一开始就错误地进行绘图功能,并且有一种更容易的方法来绘图,同时保持简单的撤消/重做,并添加擦除,请告诉我。我完全可以调整我的方法!提前感谢您的任何帮助。
// setup the layer hierarchy for drawing
private func setupView() {
self.mainDrawLayer = CAShapeLayer()
self.mainDrawLayer.backgroundColor = UIColor.clear.cgColor
self.layer.addSublayer(self.mainDrawLayer)
// set up the mask. add an opaque background so everything shows through to start
self.maskLayer = CALayer()
let p = UIBezierPath.init(rect: self.bounds)
self.maskShapeLayer = CAShapeLayer()
self.maskShapeLayer?.fillColor = UIColor.black.cgColor
self.maskShapeLayer?.path = p.cgPath
self.maskLayer?.addSublayer(self.maskShapeLayer!)
// apply the mask
self.layer.mask = self.maskLayer
}
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
guard let touch = touches.first else {
return
}
var erasing = false
// setup the currentDrawLayer which captures the bezier path
self.currentDrawLayer = CAShapeLayer()
self.currentDrawLayer?.lineCap = CAShapeLayerLineCap.round
self.currentDrawLayer?.fillColor = nil
// set the ink color to use for drawing
if let ink = UserDefaults.standard.string(forKey: "ink") {
self.currentDrawLayer?.strokeColor = UIColor(hex: ink)?.cgColor
} else {
self.currentDrawLayer?.strokeColor = UIColor(hex: Constants.inkBlack3)?.cgColor
}
if UserDefaults.standard.string(forKey: "ink") == Constants.inkBlack5 {
// removing the filter makes white overlay other colors
// this is essentially erasing with a white background
self.currentDrawLayer?.compositingFilter = nil
} else {
// this blend mode ads a whole different feeling to the drawing!
self.currentDrawLayer?.compositingFilter = "darkenBlendMode"
}
// THIS IS THE ERASER COLOR!
if UserDefaults.standard.string(forKey: "ink") == Constants.inkBlack4 {
// trying erasing via drawing with clear
self.currentDrawLayer?.strokeColor = UIColor.clear.cgColor
// is there a compositingFilter available to 'combine' my clear color with the black opaque mask layer created above?
self.currentDrawLayer?.compositingFilter = "iDontHaveADamnClueIfTheresOneThatWillWorkIveTriedThemAllItSeems:)"
erasing = true
}
self.currentDrawLayer?.path = self.mainDrawPath.cgPath
if erasing {
// add the layer to the masks
self.maskLayer!.addSublayer(self.currentDrawLayer!)
} else {
// add the layer to the drawings
self.layer.addSublayer(self.currentDrawLayer!)
}
let location = touch.location(in: self)
self.ctr = 0
self.pts[0] = location
}