当应用程序从后台恢复时,恢复动画停止的位置 [英] Restoring animation where it left off when app resumes from background

查看:170
本文介绍了当应用程序从后台恢复时,恢复动画停止的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在视图中有一个无休止地循环 CABasicAnimation 的重复图像图块:

I have an endlessly looping CABasicAnimation of a repeating image tile in my view:

a = [CABasicAnimation animationWithKeyPath:@"position"];
a.timingFunction = [CAMediaTimingFunction 
                      functionWithName:kCAMediaTimingFunctionLinear];
a.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
a.toValue = [NSValue valueWithCGPoint:CGPointMake(image.size.width, 0)];
a.repeatCount = HUGE_VALF;
a.duration = 15.0;
[a retain];

我试图暂停并恢复图层动画,如技术Q& A QA1673

I have tried to "pause and resume" the layer animation as described in Technical Q&A QA1673.

当应用程序进入后台时,动画将从图层中删除。
为了补偿我听 UIApplicationDidEnterBackgroundNotification 并调用 stopAnimation 并响应 UIApplicationWillEnterForegroundNotification 致电 startAnimation

When the app enters background, the animation gets removed from the layer. To compensate I listen to UIApplicationDidEnterBackgroundNotification and call stopAnimation and in response to UIApplicationWillEnterForegroundNotification call startAnimation.

- (void)startAnimation 
{
    if ([[self.layer animationKeys] count] == 0)
        [self.layer addAnimation:a forKey:@"position"];

    CFTimeInterval pausedTime = [self.layer timeOffset];
    self.layer.speed = 1.0;
    self.layer.timeOffset = 0.0;
    self.layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = 
      [self.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    self.layer.beginTime = timeSincePause;
}

- (void)stopAnimation 
{
    CFTimeInterval pausedTime = 
      [self.layer convertTime:CACurrentMediaTime() fromLayer:nil];
    self.layer.speed = 0.0;
    self.layer.timeOffset = pausedTime;    
}

问题是它在开始时再次启动,并且从最后一个位置,如应用程序确实进入后台时系统所采用的应用程序快照所示,回到动画循环的开始。

The problem is that it starts again at the beginning and there is ugly jump from last position, as seen on app snapshot the system took when application did enter background, back to the start of the animation loop.

我无法弄清楚如何制作它当我重新添加动画时,从最后一个位置开始。坦率地说,我只是不明白QA1673的代码是如何工作的:在 resumeLayer 中,它将layer.beginTime设置两次,这似乎是多余的。但是当我删除第一个设置为零时,它没有恢复暂停的动画。这是通过简单的点击手势识别器测试的,它确实切换了动画 - 这与我从后台恢复的问题没有严格的关系。

I can not figure out how to make it start at last position, when I re-add the animation. Frankly, I just don't understand how that code from QA1673 works: in resumeLayer it sets the layer.beginTime twice, which seems redundant. But when I've removed the first set-to-zero, it did not resume the animation where it was paused. This was tested with simple tap gesture recognizer, that did toggle the animation - this is not strictly related to my issues with restoring from background.

在此之前我应该​​记住什么状态当我稍后重新添加动画时,动画会被删除,如何从该状态恢复动画?

What state should I remember before the animation gets removed and how do I restore the animation from that state, when I re-add it later?

推荐答案

之后很多搜索和与iOS开发大师的谈话,似乎 QA1673 在暂停,背景,然后移动到前景时无效。我的实验甚至表明,从动画中发出的委托方法,例如 animationDidStop 变得不可靠。

After quite a lot of searching and talks with iOS development gurus, it appears that QA1673 doesn't help when it comes to pausing, backgrounding, then moving to foreground. My experimentation even shows that delegate methods that fire off from animations, such asanimationDidStopbecome unreliable.

有时他们会开火,有时他们没有。

Sometimes they fire, sometimes they don't.

这会产生很多问题,因为这意味着你不仅要看到暂停时的不同屏幕,还要看当前的事件顺序动作可能会中断。

This creates a lot of problems because it means that, not only are you looking at a different screen that you were when you paused, but also the sequence of events currently in motion can be disrupted.

到目前为止,我的解决方案如下:

My solution thus far has been as follows:

当动画开始时,我得到开始时间:

When the animation starts, I get the start time:

mStartTime = [layer convertTime:CACurrentMediaTime()fromLayer:nil];

当用户点击暂停按钮时,我从 CALayer 中移除动画:

When the user hits the pause button, I remove the animation from theCALayer:

[layer removeAnimationForKey:key];

我使用<$ c得到绝对时间$ c> CACurrentMediaTime():

CFTimeInterval stopTime = [layer convertTime:CACurrentMediaTime()fromLayer:nil];

使用 mStartTime stopTime 我计算了一个偏移时间:

Using themStartTimeandstopTimeI calculate an offset time:

mTimeOffset = stopTime - mStartTime;

我还将对象的模型值设置为 presentationLayer的模型值。所以,我的 stop 方法如下所示:

I also set the model values of the object to be that of thepresentationLayer. So, mystopmethod looks like this:

//--------------------------------------------------------------------------------------------------

- (void)stop
{
    const CALayer *presentationLayer = layer.presentationLayer;

    layer.bounds = presentationLayer.bounds;
    layer.opacity = presentationLayer.opacity;
    layer.contentsRect = presentationLayer.contentsRect;
    layer.position = presentationLayer.position;

    [layer removeAnimationForKey:key];

    CFTimeInterval stopTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    mTimeOffset = stopTime - mStartTime;
}

在恢复时,我会根据<$重新计算暂停动画的剩余部分C $ C> mTimeOffset 。这有点乱,因为我正在使用 CAKeyframeAnimation 。我根据 mTimeOffset 找出哪些关键帧是未完成的。此外,我考虑到暂停可能发生在帧的中间,例如介于 f1 f2 之间。该时间从该关键帧的时间开始扣除。

On resume, I recalculate what's left of the paused animation based upon themTimeOffset. That's a bit messy because I'm usingCAKeyframeAnimation. I figure out what keyframes are outstanding based on themTimeOffset. Also, I take into account that the pause may have occurred mid frame, e.g. halfway betweenf1andf2. That time is deducted from the time of that keyframe.

然后我将此动画重新添加到图层:

I then add this animation to the layer afresh:

[layer addAnimation:animationGroup forKey:key];

要记住的另一件事是你需要检查 animationDidStop 中的标志,如果标志为<$ c $,则只从 removeFromSuperlayer 中移除父级的动画图层C>是。这意味着该图层在暂停期间仍然可见。

The other thing to remember is that you will need to check the flag inanimationDidStopand only remove the animated layer from the parent withremoveFromSuperlayerif the flag isYES. That means that the layer is still visible during the pause.

此方法看起来非常费力。虽然它确实有用!我希望能够使用 QA1673 。但目前用于后台处理,它不起作用,这似乎是唯一的解决方案。

This method does seem very laborious. It does work though! I'd love to be able to simply do this using QA1673. But at the moment for backgrounding, it doesn't work and this seems to be the only solution.

这篇关于当应用程序从后台恢复时,恢复动画停止的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆