慢下来使用CoreAnimation加速动画 [英] Slow down & accelerate animations with CoreAnimation

查看:75
本文介绍了慢下来使用CoreAnimation加速动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的应用程序中应用慢动作效果,这非常类似于如果按下Shift可以减慢Mac OS的大多数图形效果。

I am trying to apply a slow-motion effect to my application, pretty much like how you can slow down most graphical effects of Mac OS if you press Shift.

我的应用程序使用CoreAnimation,所以我认为应该没什么大不了的:将 speed 设置为一些较慢的值(例如 0.1 ),然后将其设置回 1 ,然后就可以了。

My application uses CoreAnimation, so I thought it should be no biggie: set speed to some slower value (like 0.1) and set it back to 1 once I'm done, and here I go.

,这不是正确的方法。减速效果很好,但是当我想恢复到正常速度时,它会一直恢复,好像速度始终是 1 一样。这基本上意味着,如果我按住Shift足够长的时间,一旦放开它,动画就会立即完成。

It seems, unfortunately, that this is not the right way. The slowdown works great, however when I want to get back to normal speed, it resumes as if the speed was 1 the whole time. This basically means that if I held Shift for long enough, as soon as I release it, the animation instantly completes.

我找到了一个技术质量检查页面,说明如何暂停和恢复动画,但如果不是完全暂停动画,我似乎无法正确处理。我肯定不是很擅长时间扭曲。

I found a Technical QA page explaining how to pause and resume an animation, but I can't seem to get it right if it's not about entirely pausing the animation. I'm definitely not very good at time warping.

放慢速度然后用CoreAnimation恢复动画的正确方法是什么?

What would be the right way to slow down then resume an animation with CoreAnimation?

这是有用的代码:

-(void)flagsChanged:(NSEvent *)theEvent
{
    CALayer* layer = self.layer;
    [CATransaction begin];
    CATransaction.disableActions = YES;
    layer.speed = (theEvent.modifierFlags & NSShiftKeyMask) ? 0.1 : 1;
    [CATransaction commit];
}


推荐答案

棘手的问题...

我使用基本的UIView进行了测试。
我启动了从当前点到目标点的图层动画。

I set up a test with a basic UIView. I initiate an animation of its layer from it's current point to a target point.

为了放慢核心动画的速度,我实际上必须构造并替换新动画(因为您不能修改现有动画)。

In order to slow down the core animation, I actually had to construct and replace a new animation (since you can't modify the existing animation).

弄清楚当前动画已经进行了多远特别重要。通过访问beginTime,currentTime,计算经过的时间,然后计算出新动画的持续时间,可以做到这一点。

It's especially important to figure out how far along the current animation has already proceeded. This is done by accessing beginTime, currentTime, calculating the elapsed time and then figuring out how long should be the duration of the new animation.

- (void)initiate {
    if(!initiated) {
        [CATransaction begin];
        [CATransaction disableActions];
        [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut]];
        CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"];
        ba.duration = 10.0f;
        ba.fromValue = [NSValue valueWithCGPoint:view.layer.position];
        ba.toValue = [NSValue valueWithCGPoint:CGPointMake(384, 512)];
        [view.layer addAnimation:ba forKey:@"animatePosition"];
        [CATransaction commit];
        initiated = YES;
    }
}

- (void)slow {
    [CATransaction begin];
    CABasicAnimation *old = (CABasicAnimation *)[view.layer animationForKey:@"animatePosition"];
    CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"];
    CFTimeInterval animationBegin = old.beginTime;
    CFTimeInterval currentTime = CACurrentMediaTime();
    CFTimeInterval elapsed = currentTime - animationBegin;
    ba.duration = [[old valueForKey:@"duration"] floatValue] - elapsed;
    ba.duration = [[old valueForKey:@"duration"] floatValue];
    ba.autoreverses = [[old valueForKey:@"autoreverses"] boolValue];
    ba.repeatCount = [[old valueForKey:@"repeatCount"] floatValue];
    ba.fromValue = [NSValue valueWithCGPoint:((CALayer *)[view.layer presentationLayer]).position];
    ba.toValue = [old valueForKey:@"toValue"];
    ba.speed = 0.1;
    [view.layer addAnimation:ba forKey:@"animatePosition"];
    [CATransaction commit];
}

- (void)normal {
    [CATransaction begin];
    CABasicAnimation *old = (CABasicAnimation *)[view.layer animationForKey:@"animatePosition"];
    CABasicAnimation *ba = [CABasicAnimation animationWithKeyPath:@"position"];
    CFTimeInterval animationBegin = old.beginTime;
    CFTimeInterval currentTime = CACurrentMediaTime();
    CFTimeInterval elapsed = currentTime - animationBegin;
    ba.duration = [[old valueForKey:@"duration"] floatValue] - elapsed;
    ba.autoreverses = [[old valueForKey:@"autoreverses"] boolValue];
    ba.repeatCount = [[old valueForKey:@"repeatCount"] floatValue];
    ba.fromValue = [NSValue valueWithCGPoint:((CALayer *)[view.layer presentationLayer]).position];
    ba.toValue = [old valueForKey:@"toValue"];
    ba.speed = 1;
    [view.layer addAnimation:ba forKey:@"animatePosition"];
    [CATransaction commit];
}

注意:上面的代码仅在1个方向上有效,不适用于自动反转的动画...

Note: The above code works only in 1 direction, not with animations that autoreverse...

这篇关于慢下来使用CoreAnimation加速动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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