2

I want to animate drawing multiple letters on a screen. I have my data in an array. The array contains line objects, these line objects have a start and end time for the animation, and the points that make up the line. My current code is as follows:

private func animateSentData(data: WhiteboardData) {
        // I currently only draw a single letter
        let path: UIBezierPath = UIBezierPath()
        if let line = data.lines.first {
            for (n, point) in line.pts.enumerated() {
                let translation: (CGFloat, CGFloat) = (point.x / data.w, point.y / data.h)
                if n == 0 {
                    path.move(to: CGPoint(x: view.frame.width * translation.0, y: view.frame.height * translation.1))
                } else {
                    path.addLine(to: CGPoint(x: view.frame.width * translation.0, y: view.frame.height * translation.1))
                }
            }
        }
        let shapelayer: CAShapeLayer = CAShapeLayer()
        shapelayer.path = path.cgPath
        shapelayer.strokeColor = UIColor.black.cgColor
        shapelayer.fillColor = UIColor.clear.cgColor
        shapelayer.lineCap = kCALineCapRound
        shapelayer.lineWidth = brushWidth

        shapelayer.frame = view.bounds
        view.layer.addSublayer(shapelayer)
        let animation: CABasicAnimation = CABasicAnimation(keyPath: "strokeEnd")
        animation.fromValue = 0
        animation.duration = 3.0 // A test duration
        shapelayer.add(animation, forKey: "myAnimation")
    }

In the code above you can see I am only drawing the first letter. How would I go about drawing the other letters? Do I need to create a new CAShapeLayer for every single letter? It seems like it would be inefficient to do that. Is it possible for a CAShapeLayer to have muliple UIBezierPaths and then animate them individually? Any tips on this would be greatly appreciated! Thanks

Kex
  • 8,023
  • 9
  • 56
  • 129

1 Answers1

2

You can definitely use a single CAShapeLayer by combining multiple UIBezierPath using the append(_:) instance method.

The code would looks like something like this:

private func animateSentData(data: WhiteboardData) {

    var path = UIBezierPath()
    for line in data.lines {
        let subPath = UIBezierPath()

        for (n, point) in line.pts.enumerated() {
            /// Construct your subPath
            …
        }
        path.append(subPath)
    }

    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    …
}

Clarification:

While you can combine multiple path into a single UIBezierPath, you can't animate individual subpaths afterwards.

Vin Gazoil
  • 1,942
  • 2
  • 20
  • 24
  • Can these subpaths then be animated individually? e.g. I want to animate `subpath1` for 2 seconds, wait 4 seconds and then animate `subpath2`. – Kex Jul 11 '18 at 09:50
  • No, I don't think that's possible. You should use multiple `CAShapeLayer` if you want to do that. – Vin Gazoil Jul 11 '18 at 09:53