pkuphy
pkuphy

Reputation: 354

iOS animation stopped after the background/foreground transition

I'm writing a page that checks if a device has been linked to the system. The page sends requests every 2 seconds for 6 times, during that time (may be up to 10 seconds) the page shows an animating loading circle.

Here is the problem: when I press the home button and immediately reopen the app, the animation stops.

Here is what I know:

Two ways of implementing the animation:

  1. CABasicAnimation:

    CABasicAnimation* rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = @(2 * M_PI);
    rotationAnimation.duration = 1.5;
    rotationAnimation.cumulative = YES;
    [loadingCircle.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    
  2. UIView animateWithDuration...:

    - (void)rotateView:(UIView *)view {
        [UIView animateWithDuration:0.75 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
            view.transform = CGAffineTransformRotate(view.transform, M_PI);
        } completion:^(BOOL finished) {
            if (finished) {
                [self rotateView:view];
            }
        }];
    }
    ...
    - viewDidLoad {
        ...
        [self rotateView:loadingCircle];
    }
    

I know that in the first implementation, setting rotationAnimation.removedOnCompletion = NO; will resume the animation.

My question is: when I'm using the second implementation what is the equivalent way to achieve the same effect.

Upvotes: 4

Views: 2832

Answers (1)

Erik
Erik

Reputation: 2409

Using UIView animateWithDuration actually applies the same effects the view's underlying layer property, so you can pause and resume like this.

func pauseLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil)
    layer.speed = 0.0
    layer.timeOffset = pausedTime
}

func resumeLayer(layer: CALayer) {
    let pausedTime: CFTimeInterval = layer.timeOffset
    layer.speed = 1.0
    layer.timeOffset = 0.0
    layer.beginTime = 0.0
    let timeSincePause: CFTimeInterval = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime
    layer.beginTime = timeSincePause
}

You'll have to translate that into objective-c yourself, sorry. Credit here for the original solution.

You can subscribe to the UIApplicationDidEnterBackgroundNotification notification via NSNotificationCenter if you'd like to keep the code local instead of putting in the app delegate. There is a matching UIApplicationWillEnterForegroundNotification notification you can use to restart the animation when coming back.

Upvotes: 1

Related Questions