Pausing CALayer animation with delayed animation

I have a set of nested UIView animations (2 or 3 levels in depth at a given time) that I would like to pause and resume. Some of these animations use -animateWithDuration:animations:completion: while others use -animateWithDuration:delay:options:animations:completion: to slow down the execution of the animation block.

I read and implemented Technical Q & QA1673 about pausing all animations in the layer tree, but I ran into a problem with animations using the delay option, I can pause and resume the animation just fine, but when the animation resumes, any animation block that has an associated with it, the delay appears to have a delay increased by the amount of time that the layer tree was suspended. For example, if one of the blocks has a delay of 1 second, and the layer tree has been suspended for 3 seconds, the animation is delayed for 4 seconds after resuming. I assume this has something to do with the beginTime ? Any help would be appreciated.

 // Pause and Resume methods, right from the technical Q&A - (void)pauseAnimationsOnLayer:(CALayer *)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime; } - (void)resumeAnimationsOnLayer:(CALayer *)layer { CFTimeInterval pausedTime = [layer timeOffset]; layer.speed = 1.0; layer.timeOffset = 0.0; layer.beginTime = 0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; layer.beginTime = timeSincePause; } // Chained animations - (void)animateNextPopup { [UIView animateWithDuration:kRFPVictorySequenceStatePopupDuration animations:^{ [_currentStateImageView setHidden:NO]; [_currentStateImageView setTransform:CGAffineTransformIdentity]; } completion:^(BOOL finished) { [UIView animateWithDuration:kRFPVictorySequenceStateSlideOffDuration delay:kRFPVictorySequenceStateVoteDelay options:UIViewAnimationOptionCurveEaseInOut animations:^{ if (winnerIsDem) { [_currentStateImageView setFrame:CGRectMake(-_currentStateImageView.frame.size.width, _currentStateImageView.frame.origin.y, _currentStateImageView.frame.size.width, _currentStateImageView.frame.size.height)]; } else { [_currentStateImageView setFrame:CGRectMake(1024, _currentStateImageView.frame.origin.y, _currentStateImageView.frame.size.width, _currentStateImageView.frame.size.height)]; } } completion:^(BOOL finished) { // Do some stuff } ]; } ]; } 
+8
ios objective-c core-animation uiview
source share
2 answers

I suggest a different approach.

Animation blocks are easy to implement, but only useful if you don't need any control over your animation.

Otherwise, you should use a timer and create your own animation manually.

 [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerFired) userInfo:nil repeats:YES]; - (void)timerFired { if (isPaused) { // Do nothing } else { // Animate } } - (IBAction)pauseTapped:(id)sender { if (isPaused) { isPaused = NO; } else { isPaused = YES; } } 

isPaused is a flag that controls your animation state.

0
source share

I found a solution to the problem! You must reset the value of self.layer.beginTime to zero in the animation completion block.

eg.

 [UIView animateWithDuration:element.duration delay:element.delay options:UIViewAnimationOptionCurveLinear animations:^{ // Animate properties here! } } completion:^(BOOL finished){ // Reset BeginTime all the time // So, in case a pause took place the delay values are valid again! **self.layer.beginTime = 0.0f;** }]; 

The rest of the pause / resume code remains unchanged.

Best!

0
source share

All Articles