使用带有延迟的动画来暂停CALayer动画

9
我有一组嵌套的UIView动画(在给定时间内有2或3个级别),我希望能够暂停和恢复。其中一些动画使用-animateWithDuration:animations:completion:,而另一些使用-animateWithDuration:delay:options:animations:completion:以延迟执行动画块。
我阅读并实施了Technical Q&A QA1673关于暂停层树中所有动画的内容,但我遇到了一个使用延迟参数的动画问题。我可以正常地暂停和恢复动画,但是当动画恢复时,任何具有延迟的动画块似乎都会将其延迟延长与层树暂停的时间相同的时间量。因此,例如,如果其中一个块具有1秒的延迟,并且层树被暂停了3秒,则动画在恢复后延迟4秒。我猜这与beginTime属性有关?任何帮助都将不胜感激。
// Pause and Resume methods, right from the technical Q&A
- (void)pauseAnimationsOnLayer:(CALayer *)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0.0;
    layer.timeOffset = pausedTime;
}

- (void)resumeAnimationsOnLayer:(CALayer *)layer
{
    CFTimeInterval pausedTime = [layer timeOffset];
    layer.speed = 1.0;
    layer.timeOffset = 0.0;
    layer.beginTime = 0;
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    layer.beginTime = timeSincePause;
}

// Chained animations
- (void)animateNextPopup
{
    [UIView animateWithDuration:kRFPVictorySequenceStatePopupDuration
                     animations:^{
                         [_currentStateImageView setHidden:NO];
                         [_currentStateImageView setTransform:CGAffineTransformIdentity];

                     }
                     completion:^(BOOL finished) {
                         [UIView animateWithDuration:kRFPVictorySequenceStateSlideOffDuration
                                               delay:kRFPVictorySequenceStateVoteDelay
                                             options:UIViewAnimationOptionCurveEaseInOut
                                          animations:^{
                                              if (winnerIsDem) {
                                                  [_currentStateImageView setFrame:CGRectMake(-_currentStateImageView.frame.size.width, 
                                                                                              _currentStateImageView.frame.origin.y, 
                                                                                              _currentStateImageView.frame.size.width, 
                                                                                              _currentStateImageView.frame.size.height)];
                                              }
                                              else {
                                                  [_currentStateImageView setFrame:CGRectMake(1024, 
                                                                                              _currentStateImageView.frame.origin.y, 
                                                                                              _currentStateImageView.frame.size.width, 
                                                                                              _currentStateImageView.frame.size.height)];
                                              }
                                          }
                                          completion:^(BOOL finished) {
                                              // Do some stuff
                                          }
                          ];
                     }
     ];
}
2个回答

0
我找到了解决问题的方法!您需要在动画完成块中将self.layer.beginTime值重置为零。
例如:
[UIView animateWithDuration:element.duration 
                      delay:element.delay 
                    options:UIViewAnimationOptionCurveLinear
                 animations:^{
                      // Animate properties here!
                     }
                 } completion:^(BOOL finished){
                              // Reset BeginTime all the time
                              // So, in case a pause took place the delay values are valid again!
                         **self.layer.beginTime = 0.0f;**
                 }];

其余的暂停/恢复代码保持不变。

最好的!


可恶,我本以为这个会有用...但是对我没起作用 :(,它没有任何效果。现在,我打算通过动画块来移除延迟。 - cclogg
@cclogg 如果您在同一层上运行多个块动画,则必须仅设置一次,而不是在每个块动画中都设置 :) - Summon

-1

我建议采用不同的方法。

动画块易于实现,但仅在您不需要对动画进行任何控制时才有用。

否则,您应该使用计时器并手动创建自己的动画。

[NSTimer scheduledTimerWithTimeInterval:0.1
                                 target:self
                               selector:@selector(timerFired)
                               userInfo:nil
                                repeats:YES];

- (void)timerFired
{
    if (isPaused) {
        // Do nothing
    } else {
        // Animate
    }
}

- (IBAction)pauseTapped:(id)sender
{
    if (isPaused) {
        isPaused = NO;
    } else {
        isPaused = YES;
    }
}

isPaused 是一个控制动画状态的标志。


2
感谢回复,但是这个想法实际上也有其自身的问题。使用标准的NSTimer将不会和设备的显示速率同步,这可能导致动画看起来很卡顿。更好的选择是使用CADisplayLink,它类似但专门设计用于与显示器同步。然而,使用一个显示链接对象来运行大约10个串行动画可能会导致一些严重的混乱代码。最终,我的问题是:为什么暂停图层树中的动画会影响后续动画的延迟值?这似乎很奇怪,不是吗? - Sean
“一些严重的意大利面条式代码”……是的,你说得对……但毕竟我是意大利人 ;) - Giuseppe Garassino

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接