视图外的CALayer绘图



我有这样的行为与以下代码:

import UIKit
class Page: UIView {

var bezierMemory = [BezierRecord]()
var currentBezier: UIBezierPath = UIBezierPath()

var firstPoint: CGPoint = CGPoint()
var previousPoint: CGPoint = CGPoint()
var morePreviousPoint: CGPoint = CGPoint()
var previousCALayer: CALayer = CALayer()

var pointCounter = 0

var selectedPen: Pen = Pen(width: 3.0, strokeOpacity: 1, strokeColor: .red, fillColor: .init(gray: 0, alpha: 0.5), isPencil: true, connectsToStart: true, fillPencil: true)

enum StandardPageSizes {
case A4, LEGAL, LETTER
}

var firstCALayer = true
var pointsTotal = 0

override init(frame: CGRect) {
super.init(frame: .zero)
}

required init?(coder: NSCoder) {
super.init(coder: coder)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
guard let touch = touches.first else { return }
let point = touch.location(in: self)
firstPoint = point

pointCounter = 1

currentBezier = UIBezierPath()
currentBezier.lineWidth = selectedPen.width
selectedPen.getStroke().setStroke()
currentBezier.move(to: point)

previousPoint = point
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
guard let touch = touches.first else { return }
let point = touch.location(in: self)
pointCounter += 1

if (pointCounter == 3) {
let midpoint = CGPoint(x: (morePreviousPoint.x + point.x)/2.0, y: (morePreviousPoint.y + point.y)/2.0)
currentBezier.addQuadCurve(to: midpoint, controlPoint: morePreviousPoint)
let updatedCALayer = CAShapeLayer()
updatedCALayer.path = currentBezier.cgPath
updatedCALayer.lineWidth = selectedPen.width
updatedCALayer.opacity = selectedPen.strokeOpacity
updatedCALayer.strokeColor = selectedPen.getStroke().cgColor
updatedCALayer.fillColor = selectedPen.getFill()
if (firstCALayer) {
layer.addSublayer(updatedCALayer)
firstCALayer = false
} else {
layer.replaceSublayer(previousCALayer, with: updatedCALayer)
}
previousCALayer = updatedCALayer
pointCounter = 1
}

morePreviousPoint = previousPoint
previousPoint = point
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
guard let touch = touches.first else { return }
let point = touch.location(in: self)

if (pointCounter != 3) {
if (selectedPen.connectsToStart) {
currentBezier.addQuadCurve(to: firstPoint, controlPoint: previousPoint)
} else {
currentBezier.addQuadCurve(to: point, controlPoint: previousPoint)
}
let updatedCALayer = CAShapeLayer()
updatedCALayer.path = currentBezier.cgPath
updatedCALayer.lineWidth = selectedPen.width
updatedCALayer.opacity = selectedPen.strokeOpacity
updatedCALayer.strokeColor = selectedPen.getStroke().cgColor
updatedCALayer.fillColor = selectedPen.getFill()
if (firstCALayer) {
layer.addSublayer(updatedCALayer)
firstCALayer = false
} else {
// layer.setNeedsDisplay()
layer.replaceSublayer(previousCALayer, with: updatedCALayer)
}
}

firstCALayer = true
let bezierRecord = BezierRecord(bezier: currentBezier, strokeColor: selectedPen.getStroke(), fillColor: selectedPen.getFill(), strokeWidth: selectedPen.width)
bezierMemory.append(bezierRecord)
}

private func normPoint(point: CGPoint) -> CGPoint {
return CGPoint(x: point.x/frame.width, y: point.y/frame.height)
}

public class BezierRecord {
var bezier: UIBezierPath
var strokeColor: UIColor
var strokeWidth: CGFloat
var fillColor: CGColor

init(bezier: UIBezierPath, strokeColor: UIColor, fillColor: CGColor, strokeWidth: CGFloat) {
self.bezier = bezier
self.strokeColor = strokeColor
self.strokeWidth = strokeWidth
self.fillColor = fillColor
}
}

}

真正的唯一相关的部分是touchesMoved和touchesEnded,其中CALayer的处理。正如你从gif中看到的,只要我开始在边界内绘制,我就可以在页面(UIView)的边界外绘制。我不想这样-我想要的是你可以在页面的边界之外保持一个笔画(只要你在页面上开始),但笔画不会出现在页面之外。什么好主意吗?

编辑:我应该补充说,对于这些uibezier曲线,(0,0)被认为是左上角的页面(白色),而不是整个视图。因此,例如,从页面上开始并继续的bezier是负的。

您所需要做的就是在视图上设置.clipsToBounds = true

一个方法:

override init(frame: CGRect) {
super.init(frame: .zero)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
self.clipsToBounds = true
}

可以self.clipsToBounds = true放在两个init函数中,但是通常的做法(没有双关语的意思)是添加一个"common init"像这样的函数(它可以被命名为任何…我就是这样做的)。我们经常有其他的"初始设置"。我们想要调用的代码,这样可以避免重复代码。

最新更新