4

OK, I am new to UIBezierPaths but I need to have a path whose endpoint updates according to where the user's finger is. It should change in touchesMoved

So far I have:

func customInit() {
    print("init scene")
    self.backgroundColor = UIColor.cyan

    path.move(to: CGPoint(x: 0, y: 0))
    path.addLine(to: CGPoint(x: 300, y: 300))

    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.lineWidth = 3.0

    self.layer.addSublayer(shapeLayer)
}

override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    var touch : UITouch! =  touches.first! as UITouch
    var location = touch.location(in: self)

    path.move(to: location)
}

I thought this would update the path endpoint but nothing happens beyond drawing the original line. I would like to not use SKScene for this, but don't know what is going wrong.

How can I make a line always have a point at the point of user's tap?

nathangitter
  • 9,607
  • 3
  • 33
  • 42
blue
  • 7,175
  • 16
  • 81
  • 179

1 Answers1

2

You're very close! You're missing just a few things.

When touchesMoved is called, you need to update the path and re-assign it to the CAShapeLayer so that it can be re-drawn. Right now you are just making a modification to the path object, but not re-drawing it.

Final Code

class DrawingView: UIView {

    let startingPoint = CGPoint(x: 0, y: 0)

    let shapeLayer = CAShapeLayer()
    let path = UIBezierPath()

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

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

    func customInit() {

        backgroundColor = UIColor.cyan

        path.move(to: startingPoint)
        path.addLine(to: CGPoint(x: 50, y: 50))

        shapeLayer.path = path.cgPath
        shapeLayer.strokeColor = UIColor.blue.cgColor
        shapeLayer.lineWidth = 3.0

        layer.addSublayer(shapeLayer)

    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event)

        let touch =  touches.first as! UITouch
        let location = touch.location(in: self)

        path.removeAllPoints()
        path.move(to: startingPoint)
        path.addLine(to: location)

        shapeLayer.path = path.cgPath

    }

}

Final Result

gif of the line endpoint moving on touch

(tested in an Xcode 8.3.2 playground)


Update:

To make the line disappear when the touch is released, use touchesEnded. Inside this method, simply remove the points on the path and reassign it to the shapeLayer so the view is updated.

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    super.touchesEnded(touches, with: event)
    path.removeAllPoints()
    shapeLayer.path = path.cgPath
}
nathangitter
  • 9,607
  • 3
  • 33
  • 42