Search code examples
iosswiftcabasicanimation

Two CABasicAnimations inside of a group animation issue


I am trying to animate something to the below effect:

https://dribbble.com/shots/10885801-Tab-Bar-Simple-Animation

My below code produces something close to what I'm looking for, however once the animation group completes a solid line is drawn between the two specified points, instead of the layer just ending after the second animation.

        let start = fromTab.convert(fromLineView.center, to: backgroundView)
        let end = toTab.convert(toLineView.center, to: backgroundView)

        let path = UIBezierPath()
        path.move(to: start)
        path.addLine(to: end)
        
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.strokeColor = ColorConstants.green.cgColor
        shapeLayer.lineWidth = 4
        shapeLayer.lineCap = .round
        
        backgroundView.layer.addSublayer(shapeLayer)
        
        let startAnimation = CABasicAnimation(keyPath: "strokeEnd")
        startAnimation.duration = 1
        startAnimation.fromValue = 0
        startAnimation.toValue = 1
        
        let endAnimation = CABasicAnimation(keyPath: "strokeStart")
        endAnimation.beginTime = startAnimation.duration
        endAnimation.duration = 1
        endAnimation.fromValue = 0
        endAnimation.toValue = 1

        let animation = CAAnimationGroup()
        animation.animations = [startAnimation, endAnimation]
        animation.duration = startAnimation.duration + endAnimation.duration
        shapeLayer.add(animation, forKey: "lineAnimation")

Here's a video of current behavior (I've slowed down the animation to see what's happening):

enter image description here

Any suggestions on achieving my intended result would be greatly appreciated. Thanks in advance.


Solution

  • Your shape layer’s “base state” is to have a line drawn.

    You create an animation that animates strokeStart and strokeEnd, but after the animation ends, it is removed, and your layer returns to it’s base state. (With your line visible.)

    Add code to set strokeEnd to 0 before you submit your animations. That will set the “base state” to not showing a line, which is what you want.

    Edit:

    (In order for the second animation in the animation group to work correctly, you’ll also have to do the below, as discussed in the comments. Moving it to the answer for clarity.)

    Also add a third animation to your animation group that starts at the same time as your endAnimation, and for the same duration, that animates the strokeEnd value and has a fromValue and TwoValue both of 1. That will set strokeEnd to 1 for the entire duration of phase 2 of the animation (what you call the "endAnimation") so the line will be visible for phase 2.