上下文:
我有一个图形,我在后台操作发生时连续旋转:
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = @(M_PI * 2.0);
rotationAnimation.duration = 2;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = HUGE_VALF;
[myImgView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
在某些时候,这个背景动画结束了,我停止了动画:
[myImgView.layer removeAllAnimations];
但是,当我这样做时,旋转会停在任何地方并且快速回到零旋转。我可以通过将演示值提升到模型值来停止它:
CATransform3D stoppedTransform = myImgView.layer.presentationLayer.transform;
[myImgView.layer removeAllAnimations];
myImgView.layer.transform = stoppedTransform;
这很好用。但理想情况下,我希望继续旋转当前电路的其余部分,并在接近零位旋转时减速并平稳停止。停止动画,将演示文稿提升为模型,并创建一个缓动曲线为零的新动画。像这样:
CATransform3D stoppedTransform = myImgView.layer.presentationLayer.transform;
[myImgView.layer removeAllAnimations];
myImgView.layer.transform = stoppedTransform;
CGFloat currRotation = [[myImgView.layer valueForKeyPath:@"transform.rotation.z"] floatValue];
CABasicAnimation *finishAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
finishAnimation.fromValue = @(currRotation);
finishAnimation.toValue = @(0);
finishAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
finishAnimation.duration = 2; //this is what I need to calculate correctly
[myImgView.layer setValue:@(0) forKeyPath:@"transform.rotation.z"];
[myImgView.layer addAnimation:finishAnimation forKey:@"transform.rotation.z"];
我的问题:
如何使用缓出曲线计算完成动画的持续时间,使其初始速度与现有旋转的速度(当前为每秒π弧度)相匹配,因此没有可见的打嗝?还是有另一种方法可以达到预期的效果吗?
我尝试过使用CASpringAnimation
并使用其initialVelocity
属性,但它似乎将弹簧拉动质量所赋予的速度与mass
一致, stiffness
和damping
及其单位不清楚。我可以通过计算持续时间来计算缓出持续时间,就好像它是线性的并将它撞到20%或30%左右。
旁注:由于图层如何报告当前的轮值,因此此处有一些小的复杂性,为了简化问题而移除toValue
finishAnimation
周围的问题。如果它超过pi弧度(180度),则报告为负值。所以它是这样的:
CGFloat rotationRadians = currRotation / M_PI;
if (rotationRadians < 0)
{
finishAnimation.duration = (-1 * rotationRadians); //negative means more than halfway through, or more than pi radians.
finishAnimation.toValue = @(0);
}
else
{
finishAnimation.duration = (2 - rotationRadians); //positive means less than halfway through, or less than pi radians
finishAnimation.toValue = @(M_PI * 2);
}