Как возобновить CAAnimation после возвращения из многозадачности - PullRequest
5 голосов
/ 22 июля 2011

в моем приложении у меня есть массив CALayer, который я анимировал по bezierPath. Когда я закрываю и снова открываю приложение, мои слои не анимируются и не находятся в той же позиции, что и до закрытия приложения. Я реализовал два метода, 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;
        }


}

Ответы [ 4 ]

3 голосов
/ 27 июля 2011
- (void)applicationDidEnterBackground:(UIApplication *)application {

 mosquitosViewController *mvc = [[mosquitosViewController alloc] init];
  [mvc pauseLayers];

  }

Проблема с тем, что вы пытаетесь сделать выше, заключается в том, что вы создаете совершенно новый экземпляр вашего контроллера представления, который не отображался на экране.Вот почему ничего не происходит, когда вы отправляете сообщение pauseLayers.

Что вам нужно сделать, это зарегистрироваться, чтобы получать уведомления о том, когда ваше приложение выходит из фонового режима, и вызывать соответствующие методы (pauseLayers и resumeLayers) когда приходит это уведомление.

Вы должны добавить следующий код где-нибудь в вашей реализации 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]];
0 голосов
/ 28 апреля 2018

Я пишу расширение Swift 4 версии, основанное на ответах @cclogg и @Matej Bukovinski из этой темы . Все, что вам нужно, это позвонить 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()
    }
}
0 голосов
/ 02 ноября 2011

Смотрите мой ответ на этот пост, чтобы узнать, как перезапустить анимацию после многозадачности:

Восстановление анимации там, где она остановилась, когда приложение возобновляет работу из фона

0 голосов
/ 24 июля 2011
- (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.
 */

}

...