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

- (void)applicationDidEnterBackground:(UIApplication *)application { mosquitosViewController *mvc = [[mosquitosViewController alloc] init]; [mvc pauseLayers]; }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
pauseLayersmessage.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 (
pauseLayersandresumeLayers) when that notification arrives.You should add the following code somewhere in your
mosquitosViewControllerimplementation (I usually do so in viewDidLoad):// Register for notification that app did enter background [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pauseLayers) name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]]; // Register for notification that app did enter foreground [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resumeLayers) name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];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