Ollie
Ollie

Reputation: 1946

Strange behaviour when animating between two circular UIBezierPaths

The Problem
I am creating an exploding rings effect. I'm using multiple CAShapeLayer's and creating a UIBezierPath for each layer. When the view is initialised, all the layers have a path with width 0. When an action is triggered, the rings animate to a larger path.

As seen in the demo below, the right hand edge of each layer is slower to animate than the remainder of each circular layer.

Demo
Video

Code

Drawing the layers:

func draw(inView view: UIView) -> CAShapeLayer {

    let shapeLayer = CAShapeLayer()

    // size.width defaults to 0
    let circlePath = UIBezierPath(arcCenter: view.center, radius: size.width / 2, startAngle: 0, endAngle: CGFloat(360.0).toRadians(), clockwise: true)

    shapeLayer.path = circlePath.CGPath
    shapeLayer.frame = view.frame

    return shapeLayer
}

Updating the layers

func updateAnimated(updatedOpacity: CGFloat, updatedSize: CGSize, duration: CGFloat) {

    let updatePath = UIBezierPath(arcCenter: view.center, radius: updatedSize.width / 2,
                                  startAngle: 0, endAngle: CGFloat(360).toRadians(), clockwise: true)

    let pathAnimation = CABasicAnimation(keyPath: "path")
    pathAnimation.fromValue = layer.path // the current path (initially with width 0)
    pathAnimation.toValue = updatePath.CGPath


    let opacityAnimation = CABasicAnimation(keyPath: "opacity")
    opacityAnimation.fromValue = self.opacity
    opacityAnimation.toValue = updatedOpacity


    let animationGroup = CAAnimationGroup()
    animationGroup.animations = [pathAnimation, opacityAnimation]
    animationGroup.duration = Double(duration)
    animationGroup.fillMode = kCAFillModeForwards
    animationGroup.removedOnCompletion = false

    layer.addAnimation(animationGroup, forKey: "shape_update")

    ... update variables ...

}

Upvotes: 7

Views: 100

Answers (1)

Rob Napier
Rob Napier

Reputation: 299693

Avoid starting with a path width of 0. It is very difficult to scale from 0 and tiny floating-point errors magnify. Values very close to zero are not very continuous in floating point (hmmm.... I guess that actually is a little like the real universe). Try starting with larger values and see how close to zero you can go safely.

Upvotes: 3

Related Questions