Josh O'Connor
Josh O'Connor

Reputation: 4962

Skip forward in CABasicAnimation (iOS)

I currently have an animation which is used as a progress indicator for a video, works great. However, now we have a feature that allows the user to skip 2.5 seconds forward into the video by tapping it, and thus I am trying to implement the progress indicator animation to skip forward 2.5 seconds into the animation. How would I skip the animation forward 2.5 seconds? I've tried "animationGroup.timeOffset = 2.5" but it doesn't work.

func performProgressIndicatorAnimation(duration: Float64) {
    layer.mask = nil
    layer.speed = 1.0

    self.duration = duration
    let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
    strokeStartAnimation.fromValue = 0
    strokeStartAnimation.toValue = 1
    strokeStartAnimation.duration = duration
    strokeStartAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

    animationGroup = CAAnimationGroup()
    animationGroup.duration = duration
    animationGroup.animations = [strokeStartAnimation]
    externalCircle.addAnimation(animationGroup, forKey: "animationGroup")

}

//Here is where my externalCircle is drawn:

private func drawCircles() {

    let externalCirclePath = UIBezierPath(roundedRect: CGRectMake(0, 0, bounds.height, bounds.height), cornerRadius: bounds.height / 2)
    externalCircle.path = externalCirclePath.CGPath
    externalCircle.fillColor = UIColor.clearColor().CGColor
    externalCircle.strokeColor = UIColor.whiteColor().CGColor
    externalCircle.lineWidth = 2

    let internalCircleRadius = bounds.size.height / 5
    let internalCirclePath = UIBezierPath(roundedRect: CGRectMake(0, 0, internalCircleRadius * 2, internalCircleRadius * 2), cornerRadius: internalCircleRadius)
    internalCircle.path = internalCirclePath.CGPath
    internalCircle.fillColor = UIColor.whiteColor().CGColor
    internalCircle.position = CGPointMake(CGRectGetMidX(bounds) - internalCircleRadius,
                                          CGRectGetMidY(bounds) - internalCircleRadius);

    layer.addSublayer(internalCircle)
    layer.addSublayer(externalCircle)
}

Upvotes: 0

Views: 149

Answers (2)

nghiahoang
nghiahoang

Reputation: 568

If you skip a proportion of animation using the timeOffset, it will still play for the same total duration. The animation simply loops around and plays again up until the point where it originally started. Ex: animation : A->B->C. If you use timeOffSet in order to begin at B, it will be : B->C->A

In this circumstance, I think you may dismiss this animation, then add new one.

Upvotes: 1

Josh O'Connor
Josh O'Connor

Reputation: 4962

Did this by removing the previous animation and starting it based on the percentage elapsed (with skip)

func skipProgressIndicatorAnimation(currentTime: CMTime, timeToSkip: Double, duration: CMTime) {

    animationGroup = nil
    externalCircle.removeAllAnimations()

    let percentageElapsedWithSkip = (CMTimeGetSeconds(currentTime) + timeToSkip) / CMTimeGetSeconds(duration)

    let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
    strokeStartAnimation.fromValue = percentageElapsedWithSkip
    strokeStartAnimation.toValue = 1
    strokeStartAnimation.duration = CMTimeGetSeconds(duration) - CMTimeGetSeconds(currentTime) - timeToSkip
    strokeStartAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)

    animationGroup = CAAnimationGroup()
    animationGroup.duration = CMTimeGetSeconds(duration) - CMTimeGetSeconds(currentTime) - timeToSkip
    animationGroup.animations = [strokeStartAnimation]
    externalCircle.addAnimation(animationGroup, forKey: "animationGroup")

}

Upvotes: 0

Related Questions