Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stop CAKeyframeAnimation with negative time offset at the end of path

There is a screen in my app, where a user can see clouds flying along an arc. This move implemented with help of CAKeyframeAnimation and works correctly. But I want to improve animation so that when user opens the screen, clouds must look already animating. That mean clouds should be somewhere at the middle of the arc. I'm implementing it like this:

theKeyframeAnimation.timeOffset = randomTimeOffset;

And the animation begins from given time (offset is negative). But! When a cloud reaches the end of the path, the animation doesn't stops. Cloud continue to move from the start of the path! Seems like animation duration doesn't change.

I'm trying to fix this by removing animation after particular time:

NSTimeInterval removingDelay = theKeyframeAnimation.duration + theKeyframeAnimation.offset;
dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW,
                                             (int64_t)(removingDelay * NSEC_PER_SEC));
dispatch_after(dispatchTime, dispatch_get_main_queue(), ^
               {
                   [cloud.layer removeAnimationForKey:@"animation_along_arc"];
               });

But this solution works poorly. Animation time and dispatch time is not synchronised. Practically animation is removed about 0.5 sec later than required.


Update: Now I'm see possible solution. I can wrap each animation with CAAnimationGroup. Then set duration of the Animation Group:

animationGroup.animations = @[theKeyframeAnima];
animationGroup.duration = theKeyframeAnima.duration + theKeyframeAnima.timeOffset;

It is the most elegant solution which I found. Any suggestions are welcome.

Update 2: This last solution doesn't work as well. Probably I should clip the pass instead of changing time offset...

like image 349
kelin Avatar asked Sep 30 '22 04:09

kelin


1 Answers

I found the solution! The problem was not in the CAKeyframeAnimation but in the CAMediaTiming. In this blog explained that timeOffset actually changes animation cycle, not time.

To achieve my purpose I should use beginTime property:

 NSTimeInterval currentTime = [targetLayer convertTime:CACurrentMediaTime()
                                             fromLayer:nil];
 anim.beginTime = currentTime + timeOffset;
 anim.duration = duration + timeOffset;
like image 81
kelin Avatar answered Oct 03 '22 07:10

kelin