且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

慢下来使用CoreAnimation加速动画

更新时间:2023-11-18 07:56:40

棘手的问题...

我使用基本的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...