Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ...

}
like image 257
Ollie Avatar asked Aug 18 '16 11:08

Ollie


1 Answers

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.

like image 182
Rob Napier Avatar answered Oct 11 '22 01:10

Rob Napier