【问题标题】:How to resume a CAAnimation after coming back from multitasking从多任务处理回来后如何恢复 CAAnimation
【发布时间】:2011-10-11 04:26:23
【问题描述】:

在我的应用程序中,我有一个沿着 bezierPath 动画的 CALayer 数组。当我关闭并重新打开应用程序时,我的图层没有动画,并且与关闭应用程序之前的位置不同。我已经实现了两种方法,pauseLayer 和 resumeLayer,当我在我的应用程序中使用两个按钮触发它们时它们会起作用,但在关闭应用程序后它们将不起作用。代码如下

   - (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;
        }


}

【问题讨论】:

  • 应用进入后台时是否调用了NSLog?
  • 是的。那是奇怪的事情:(
  • 向我展示您调用 pauseLayers 和 resumeLayers 的应用委托方法。
  • 好的,就是这样。我已将其发布在新答案中
  • 您应该编辑原始答案,而不是在新答案中添加此代码。

标签: background core-animation calayer multitasking caanimation


【解决方案1】:
- (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.
 */

}

【讨论】:

    【解决方案2】:
    - (void)applicationDidEnterBackground:(UIApplication *)application {
    
     mosquitosViewController *mvc = [[mosquitosViewController alloc] init];
      [mvc pauseLayers];
    
      }
    

    您在上面尝试做的问题是您正在创建视图控制器的全新实例,这不是屏幕上显示的那个。这就是为什么当您发送 pauseLayers 消息时没有任何反应的原因。

    您应该做的是注册以接收有关您的应用何时进入和来自后台的通知,并在该通知到达时调用适当的方法(pauseLayersresumeLayers)。

    您应该在 mosquitosViewController 实现中的某处添加以下代码(我通常在 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]];
    

    【讨论】:

      【解决方案3】:

      有关如何在多任务处理后重新启动动画的详细信息,请参阅我对这篇文章的回答:

      Restoring animation where it left off when app resumes from background

      【讨论】:

        【解决方案4】:

        我根据来自this thread 的@cclogg 和@Matej Bukovinski 的回答编写了一个Swift 4 版本扩展。您只需拨打layer.makeAnimationsPersistent()

        这里有完整的要点:CALayer+AnimationPlayback.swift, CALayer+PersistentAnimations.swift

        核心部分:

        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()
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-29
          • 2015-06-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多