How to resume a CAAnimation after coming back from multitasking
- Daniele Nazzari
- 2011-07-22 15:59
- 4
in my app i have an array of CALayer that I have animated along a bezierPath. When I close and reopen the app my layers are not animating and not in the same position as before closing the app. I have implemented two methods, pauseLayer and resumeLayer that works when I trigger them with two buttons inside my app but they won't work after closing the app. The code is the following
- (void)pauseLayers{ for(int y=0; y<=end;y++) { CFTimeInterval pausedTime = [car[y] convertTime:CACurrentMediaTime() fromLayer:nil]; car[y].speed = 0.0; car[y].timeOffset = pausedTime; standardUserDefaults[y] = [NSUserDefaults standardUserDefaults]; if (standardUserDefaults[y]) { [standardUserDefaults[y] setDouble:pausedTime forKey:@"pausedTime"]; [standardUserDefaults[y] synchronize]; } NSLog(@"saving positions"); } } -(void)resumeLayers { for(int y=0; y<=end;y++) { standardUserDefaults[y] = [NSUserDefaults standardUserDefaults]; car[y].timeOffset = [standardUserDefaults[y] doubleForKey:@"pausedTime"]; CFTimeInterval pausedTime = [car[y] timeOffset]; car[y].speed = 1.0; car[y].timeOffset = 0.0; car[y].beginTime = 0.0; CFTimeInterval timeSincePause = [car[y] convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; car[y].beginTime = timeSincePause; } }
4 Answers
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSLog(@"1"); mosquitosViewController *mvc = [[mosquitosViewController alloc] init]; [mvc pauseLayers]; /* Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. */
}
animation stop after enter background, I have a keyframe animation that changes color after certain events but I can't figure out how to stop the animation after the event is done? HTML (just to call up the events): I think it would be nice to have this as a controllable flag, so the view could handle the pause/resume if it was playing when entering background
Daniele Nazzari
2011-07-24 10:01
See my answer to this post for details on how to restart an animation after multitasking:
Restoring animation where it left off when app resumes from background
lottie animation stops, Supercharge your animation workflow with the LottieFiles plugin. Export your animation as Lottie JSON, access your private files, test and perfect them straight from your After Effects. animations online. Easily tweak your animations layers, size, color, text and much more. Edit an animation. Implement Lottie animations on web in just a few clicks. [] Crashing Bug; [] Feature Request; [] Regression (Something that once worked, but doesn't work anymore). Which Version of Lottie are you
Max MacLeod
2017-05-23 10:26
I write a Swift 4 version extension based on @cclogg and @Matej Bukovinski answers from this thread. All you need is to call layer.makeAnimationsPersistent()
Full Gist here: CALayer+AnimationPlayback.swift, CALayer+PersistentAnimations.swift
Core part:
public extension CALayer { static private var persistentHelperKey = "CALayer.LayerPersistentHelper" public func makeAnimationsPersistent() { var object = objc_getAssociatedObject(self, &CALayer.persistentHelperKey) if object == nil { object = LayerPersistentHelper(with: self) let nonatomic = objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC objc_setAssociatedObject(self, &CALayer.persistentHelperKey, object, nonatomic) } } } public class LayerPersistentHelper { private var persistentAnimations: [String: CAAnimation] = [:] private var persistentSpeed: Float = 0.0 private weak var layer: CALayer? public init(with layer: CALayer) { self.layer = layer addNotificationObservers() } deinit { removeNotificationObservers() } } private extension LayerPersistentHelper { func addNotificationObservers() { let center = NotificationCenter.default let enterForeground = NSNotification.Name.UIApplicationWillEnterForeground let enterBackground = NSNotification.Name.UIApplicationDidEnterBackground center.addObserver(self, selector: #selector(didBecomeActive), name: enterForeground, object: nil) center.addObserver(self, selector: #selector(willResignActive), name: enterBackground, object: nil) } func removeNotificationObservers() { NotificationCenter.default.removeObserver(self) } func persistAnimations(with keys: [String]?) { guard let layer = self.layer else { return } keys?.forEach { (key) in if let animation = layer.animation(forKey: key) { persistentAnimations[key] = animation } } } func restoreAnimations(with keys: [String]?) { guard let layer = self.layer else { return } keys?.forEach { (key) in if let animation = persistentAnimations[key] { layer.add(animation, forKey: key) } } } } @objc extension LayerPersistentHelper { func didBecomeActive() { guard let layer = self.layer else { return } restoreAnimations(with: Array(persistentAnimations.keys)) persistentAnimations.removeAll() if persistentSpeed == 1.0 { // if layer was playing before background, resume it layer.resumeAnimations() } } func willResignActive() { guard let layer = self.layer else { return } persistentSpeed = layer.speed layer.speed = 1.0 // in case layer was paused from outside, set speed to 1.0 to get all animations persistAnimations(with: layer.animationKeys()) layer.speed = persistentSpeed // restore original speed layer.pauseAnimations() } }
stop uiview animation swift, To cancel an animation you simply need to set the property that is currently being animated, outside of the UIView animation. That will stop the animation wherever it is, and the UIView will jump to the setting you just defined. You can stop all animations on a view by calling: [view.layer removeAllAnimations];. (You'll need to
ArtFeel
2018-04-28 09:02
The problem with what you are trying to do above is that you are creating a completely new instance of your view controller, which is not the one that was showing onscreen. That's why nothing happens when you send the
pauseLayers
message.What you should do is register to receive notifications for when your app goes to and comes from the background and call the appropriate methods (
pauseLayers
andresumeLayers
) when that notification arrives.You should add the following code somewhere in your
mosquitosViewController
implementation (I usually do so in viewDidLoad):How to resume a CAAnimation after coming back from multitasking, - (void)applicationDidEnterBackground:(UIApplication *)application { mosquitosViewController *mvc = [[mosquitosViewController alloc] init]; in my app i have an array of CALayer that I have animated along a bezierPath. When I close and reopen the app my layers are not animating and not in the
MiguelB
2011-07-27 18:11