我正在尝试使用图层蒙版创建一个橡皮擦。 使用口罩时,我得到以下结果: 我的环境是这样设置的: 从底视图/层到顶...
这是我当前的代码在绘制时要获得平滑线条的样子,但是会产生不良的橡皮擦效果...
import UIKit
import QuartzCore
class DrawPanZom: UIScrollView {
var drawPath = UIBezierPath()
var images = [UIImage?]()
weak var newImage: UIImageView?
var newImages: [UIImageView?] = []
var brush: CGFloat = 10.0
var color = UIColor.black
var opacity: CGFloat = 1.0
var swiped = false
var eraser = false
var canvasCleared = false
var drawLine: Bool = false
var drawFreeHand: Bool = false
var twoPoints = [CGPoint]()
var highlighter: Bool = false
var pinchZoom: Bool = false
weak var strokeColor: UIColor?
var isFirst = false
var lastPoint: CGPoint?
var firstPoint = CGPoint.zero
var secondPoint: CGPoint?
var pageDrawingPath: String?
private let forceSensitivity: CGFloat = 4.0
private let defaultLineWidth: CGFloat = 6
//private var _image1: UIImage?
var lineArray: [CGPoint] = []
let loadPage = LoadPage()
private var drawingLayer: CAShapeLayer?
var midPoint: CGPoint?
var canUndo = false
var canRedo = false
@IBOutlet weak var pageImagesView: UIView!
@IBOutlet weak var backgroundImageView: UIImageView!
@IBOutlet weak var mainImageView: UIImageView!
@IBOutlet weak var eraserImageView: UIImageView!
@IBOutlet weak var drawingView: UIView!
var completionHandler:((String) -> Bool)?
var undoHandler:(([CALayer]) -> Bool)?
var canUndoHandler:((Bool) -> Bool)?
var imageMovedHandler:((_ image: UIImageView, _ index: Int) -> Bool)?
var line = [CGPoint]() //{
// didSet { checkIfTooManyPoints() }
// }
//var newLayer: CALayer = CALayer()
var subLayers: [CALayer] {
return mainImageView.layer.sublayers ?? [CALayer]()
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
if eraser {
//var rect: CGRect = CGRect()
let linePath = UIBezierPath(rect: mainImageView.bounds)
for (index, point) in line.enumerated() {
if index == 0 {
midPoint = CGPoint(
x: (point.x + point.x) / 2,
y: (point.y + point.y) / 2
)
//rect = CGRect(x: midPoint!.x, y: midPoint!.y, width: brush, height: brush)
linePath.move(to: midPoint!)
} else {
midPoint = CGPoint(
x: (point.x + line[index - 1].x) / 2,
y: (point.y + line[index - 1].y) / 2
)
//rect = CGRect(x: midPoint!.x, y: midPoint!.y, width: brush, height: brush)
linePath.addQuadCurve(to: midPoint!, controlPoint: line[index - 1])
}
}
let maskLayer = CAShapeLayer()
maskLayer.lineWidth = brush
maskLayer.lineCap = .round
maskLayer.strokeColor = UIColor.clear.cgColor
maskLayer.fillColor = UIColor.black.cgColor
maskLayer.opacity = 1.0
maskLayer.path = linePath.cgPath
maskLayer.fillRule = .evenOdd
mainImageView.layer.addSublayer(maskLayer)
mainImageView.layer.mask = maskLayer
} else {
let drawingLayer = self.drawingLayer ?? CAShapeLayer()
let linePath = UIBezierPath()
drawingLayer.contentsScale = UIScreen.main.scale
drawingLayer.zPosition = 4
if drawLine {
var newLine = CGPoint()
if line.count > 0 {
let xVariance = (line[0].x - line.last!.x)
let yVariance = (line.last!.y - line[0].y)
print("xVariance: \(xVariance), yVariance: \(yVariance)")
if (line[0].x - line.last!.x) <= 10, (line[0].x - line.last!.x) >= -10 {
newLine = CGPoint(x: line[0].x, y: line.last!.y)
} else {
newLine = line.last!
}
if (line.last!.y - line[0].y) <= 10, (line.last!.y - line[0].y ) >= -10 {
newLine = CGPoint(x: line.last!.x, y: line[0].y)
} else {
newLine = line.last!
}
linePath.move(to: line[0])
linePath.addLine(to: newLine)
}
} else if drawFreeHand || eraser {
for (index, point) in line.enumerated() {
if index == 0 {
midPoint = CGPoint(
x: (point.x + point.x) / 2,
y: (point.y + point.y) / 2
)
linePath.move(to: midPoint!)
} else {
midPoint = CGPoint(
x: (point.x + line[index - 1].x) / 2,
y: (point.y + line[index - 1].y) / 2
)
linePath.addQuadCurve(to: midPoint!, controlPoint: line[index - 1])
}
}
}
linePath.stroke(with: .clear, alpha: 1.0)
drawingLayer.path = linePath.cgPath
drawingLayer.opacity = Float(opacity)
drawingLayer.lineWidth = brush
drawingLayer.lineCap = .round
drawingLayer.lineJoin = .round
drawingLayer.strokeColor = color.cgColor
drawingLayer.fillColor = UIColor.clear.cgColor
drawingLayer.isOpaque = false
if self.drawingLayer == nil {
self.drawingLayer = drawingLayer
mainImageView.layer.addSublayer(drawingLayer)
}
}
}
func checkIfTooManyPoints() {
var maxPoints = 0
if drawLine {
maxPoints = 500
} else {
maxPoints = 21
}
if line.count > maxPoints {
updateFlattenLayer()
_ = line.removeFirst(maxPoints - 2)
}
}
func flattenImage() {
updateFlattenLayer()
line.removeAll()
}
func updateFlattenLayer() {
let layer = subLayers
if layer.count > 0 {
_ = canUndoHandler?(true)
} else {
_ = canUndoHandler?(false)
}
guard let drawingLayer = drawingLayer, let optionalDrawing = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(NSKeyedArchiver.archivedData(withRootObject: drawingLayer, requiringSecureCoding: false)) as? CAShapeLayer?, let newDrawing = optionalDrawing else { return }
mainImageView.layer.addSublayer(newDrawing)
_ = undoHandler?(layer)
}
func removeDrawingLayer(){
drawingLayer?.removeFromSuperlayer()
line.removeAll()
layer.setNeedsDisplay()
}
func clear() {
emptyFlattenLayers()
drawingLayer?.removeFromSuperlayer()
drawingLayer = nil
line.removeAll()
layer.setNeedsDisplay()
}
func emptyFlattenLayers() {
for case let layer as CAShapeLayer in subLayers {
layer.removeFromSuperlayer()
}
}
func calculateRectBetween(lastPoint: CGPoint, newPoint: CGPoint) -> CGRect {
let originX = min(lastPoint.x, newPoint.x) - (brush / 2)
let originY = min(lastPoint.y, newPoint.y) - (brush / 2)
let maxX = max(lastPoint.x, newPoint.x) + (brush / 2)
let maxY = max(lastPoint.y, newPoint.y) + (brush / 2)
let width = maxX - originX
let height = maxY - originY
return CGRect(x: originX, y: originY, width: width, height: height)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
guard let touch = touches.first else { return }
_ = completionHandler?("toggleMenus")
if touches.count == 1 {
line.removeAll()
lineArray.removeAll()
let location = touch.location(in: mainImageView)
line.append(location)
lineArray.append(location)
firstPoint = location
lastPoint = location
swiped = false
isFirst = true
} else {
line.removeAll()
lineArray.removeAll()
}
//}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
guard let touch = touches.first else { return }
let anyObjectTouch = event?.allTouches?.first
var myMovableImage: UIImageView?
if newImages.count > 0 {
newImages.forEach { (image) in
if anyObjectTouch?.view == image {
myMovableImage = image
}
}
}
if anyObjectTouch?.view == myMovableImage {
if myMovableImage != nil {
if myMovableImage!.layer.borderWidth > 0 {
let location: CGPoint? = anyObjectTouch?.location(in: mainImageView)
myMovableImage!.center = location!
}
}
} else if touches.count == 1 {
swiped = true
let currentLocation = touch.location(in: mainImageView)
line.append(currentLocation)
if eraser {
}
lastPoint = line.last ?? .zero
let rect = calculateRectBetween(lastPoint: lastPoint!, newPoint: currentLocation)
layer.setNeedsDisplay(rect)
if highlighter {
opacity = 0.2
} else {
opacity = 1
}
} else {
line.removeAll()
lineArray.removeAll()
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
//let layers = subLayers
guard let touch = touches.first else { return }
let anyObjectTouch = event?.allTouches?.first
var myMovableImage: UIImageView?
if newImages.count > 0 {
newImages.forEach { (image) in
if anyObjectTouch?.view == image {
myMovableImage = image
//index = index + 1
}
}
}
if anyObjectTouch?.view == myMovableImage {
if myMovableImage != nil {
let imageIndex = newImages.firstIndex(of: myMovableImage)
_ = imageMovedHandler?(myMovableImage!, imageIndex!)
}
}
if touches.count == 1 {
if swiped {
if highlighter {
opacity = 0.5
} else {
opacity = 1
}
}
let currentLocation = touch.location(in: mainImageView)
line.append(currentLocation)
lineArray.append(currentLocation)
flattenImage()
} else {
line.removeAll()
lineArray.removeAll()
}
}
}
//drawing helper
extension DrawPanZom {
func clearLayers() {
let theseLayers = mainImageView.layer.sublayers
if theseLayers!.count > 0 {
backgroundImageView.layer.sublayers?.forEach {
$0.removeFromSuperlayer()
}
}
}
func setFromDrawing(fromDrawing: [CALayer]) {
mainImageView.layer.sublayers = fromDrawing
setNeedsDisplay()
}
}
没有任何“错误”。但是,它不能“干净地”擦除被触摸的区域。看起来这条线实际上是在渲染为某种形状。有人知道我在做什么错吗?