Search code examples
iosswiftswift3core-animationuibezierpath

Animated drawing of UIBezierPath array


I have UIBezierPath array that created from touchesBegan and touchesMoved point. I want animate the draw of them on the screen.

What is the best way to do that without iterate each bezier and call setNeedsDisplay()?

thanks

  override func draw(_ rect: CGRect) {
      for bezier in beziers{
         bezier.stroke()
      }
   }
   override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
      super.touchesBegan(touches, with: event)
      let cgPoint = touches.first!.location(in: self)
      let bezierPath = ColorBezierPath() // subclass of UIBezierPath
      bezierPath.lineWidth = lineWidth
      bezierPath.color = color
      bezierPath.move(to: cgPoint)
      beziers.append(bezierPath)
   }

   override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
      super.touchesMoved(touches, with: event)
      let cgPoint = touches.first!.location(in: self)
      let bezierPath = beziers.last
      bezierPath?.addLine(to: cgPoint)
      setNeedsDisplay()
   }

Solution

  • Your best bet would be to use CAShapeLayer. It takes a path and various other settings. To animate it, just animate its strokeEnd property from 0.0 to 1.0. That will create the effect of drawing the path from start to finish given whatever animation timing parameters you want:

    let shapeLayer = CAShapeLayer()               // strokeEnd's model value is 1.0 by default
    shapeLayer.frame = containerLayer.bounds
    shapeLayer.path = bezierPath.cgPath
    containerLayer.addSublayer(shapeLayer)
    
    let strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd")
    strokeEndAnimation.duration = 2.0
    strokeEndAnimation.fromValue = 0.0
    
    shapeLayer.add(strokeEndAnimation, forKey: "strokeEndAnimation")