let path = UIBezierPath()
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.lineWidth = 3
path.move(to: startPoint)
path.addLine(to: point)
shapeLayer.lineJoin = kCALineJoinRound
shapeLayer.path = path.cgPath
tempImage.layer.addSublayer(shapeLayer)
I am using the above code. Calling the above code each tome the touch is moved. I am not getting a continuous drawing . only the final portion of my drawing is visible.Is there anything i am missing here.
I achieved a smooth drawing with UIBezierPath
and CAShapeLayer
. Here the approach is having a temporary bezier path. If you want to draw on top of an image probably you can try something like this drawingLayer.content = yourImage.cgImage
.
Swift 4
class DrawingView: UIView {
private var drawingLayer: CAShapeLayer?
private var currentPath: UIBezierPath?
private var temporaryPath: UIBezierPath?
private var points = [CGPoint]()
var drawColor = UIColor.blue
var lineWidth: CGFloat = 2.0
var opacity: CGFloat = 0.8
var sublayers: [CALayer] {
return self.layer.sublayers ?? [CALayer]()
}
// MARK: Init
override public init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
self.layer.removeAllAnimations()
self.layer.masksToBounds = true // Restrict the drawing within the canvas
self.backgroundColor = UIColor.white
self.isMultipleTouchEnabled = false
}
// MARK: Drawing
override func draw(_ rect: CGRect) {
// TODO: This orveriding is still required. Need to find a way to remove this
}
override func draw(_ layer: CALayer, in ctx: CGContext) {
let drawingLayer = self.drawingLayer ?? CAShapeLayer()
drawingLayer.contentsScale = UIScreen.main.scale
drawingLayer.lineWidth = lineWidth
drawingLayer.opacity = Float(opacity)
drawingLayer.lineJoin = .round
drawingLayer.lineCap = .round
drawingLayer.fillColor = UIColor.clear.cgColor
drawingLayer.miterLimit = 0
drawingLayer.strokeColor = drawColor.cgColor
let linePath = UIBezierPath()
if let tempPath = temporaryPath, let bezierPath = currentPath {
linePath.append(tempPath)
linePath.append(bezierPath)
drawingLayer.path = linePath.cgPath
}
if self.drawingLayer == nil {
self.drawingLayer = drawingLayer
self.layer.addSublayer(drawingLayer)
}
}
// MARK: - Touches
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.preciseLocation(in: self) else {
return
}
points.removeAll()
points.append(point)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.preciseLocation(in: self) else {
return
}
points.append(point)
updatePaths()
layer.setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// single touch support
if points.count == 1 {
currentPath = createPathStarting(at: points[0])
currentPath?.lineWidth = self.lineWidth / 2.0
currentPath?.addArc(withCenter: points[0], radius: lineWidth / 4.0, startAngle: 0, endAngle: .pi * 2.0, clockwise: true)
}
finishPath()
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
finishPath()
}
// MARK: - Bezier paths Management
private func updatePaths() {
// update main path
while points.count > 4 {
points[3] = CGPoint(x: (points[2].x + points[4].x)/2.0, y: (points[2].y + points[4].y)/2.0)
if currentPath == nil {
currentPath = createPathStarting(at: points[0])
}
currentPath?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2])
points.removeFirst(3)
temporaryPath = nil
}
// build temporary path up to last touch point
switch points.count {
case 2:
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addLine(to: points[1])
break
case 3:
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addQuadCurve(to: points[2], controlPoint: points[1])
break
case 4:
temporaryPath = createPathStarting(at: points[0])
temporaryPath?.addCurve(to: points[3], controlPoint1: points[1], controlPoint2: points[2])
break
default:
break
}
}
private func finishPath() {
// add temp path to current path to reflect the changes in canvas
if let tempPath = temporaryPath {
currentPath?.append(tempPath)
}
currentPath = nil
}
private func createPathStarting(at point: CGPoint) -> UIBezierPath {
let localPath = UIBezierPath()
localPath.move(to: point)
return localPath
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.