CAMediaTimingFunction
可以实现你想要的效果,但它不支持多功能(动画)使用中获取给定'x'的'y'值,而是将已解决的值不透明地传递给后台的动画系统。
我自己也需要它,所以构建了一个具有与CAMediaTimingFunction
完全相同接口和功能的类,但具有所需的-valueForX:
方法。以下是用法示例:
RSTimingFunction *heavyEaseInTimingFunction = [RSTimingFunction timingFunctionWithControlPoint1:CGPointMake(0.8, 0.0) controlPoint2:CGPointMake(1.0, 1.0)];
CGFloat visualProgress = [heavyEaseInTimingFunction valueForX:progress];
您可以创建缓入、缓出、缓入缓出或任何可以用三次贝塞尔曲线描述的曲线。实现的数学基础是基于WebCore(WebKit),这也可能是CoreAnimation在内部使用的东西。animate...usingSpringWithDamping:..
) - RobertCASpringAnimation
,这是一个简单的弹簧求解器。UIKit Dynamics、SpriteKit和SceneKit使用实际的实时物理引擎,但Core Animation只是提前计算所有关键帧值。 - CIFilter很遗憾,但是Core Animation没有暴露其动画定时的内部计算模型。然而,对我来说非常有效的方法是使用Core Animation来完成工作!
CALayer
to serve as an evaluator((0.0, 0.0), (1.0, 1.0))
isHidden
to true
speed
to 0.0
When you want to evaluate any CAMediaTimingFunction
, create a reference animation:
let basicAnimation = CABasicAnimation(keyPath: "bounds.origin.x")
basicAnimation.duration = 1.0
basicAnimation.timingFunction = timingFunction
basicAnimation.fromValue = 0.0
basicAnimation.toValue = containerLayer.bounds.width
referenceLayer.add(basicAnimation, forKey: "evaluatorAnimation")
Set the reference layer's timeOffset
to whatever normalized input value (i.e., between 0.0
and 1.0
) you want to evaluate:
referenceLayer.timeOffset = 0.3 // 30% into the animation
Ask for the reference layer's presentation layer, and get its current bounds origin x value:
if let presentationLayer = referenceLayer.presentation() as CALayer? {
let evaluatedValue = presentationLayer.bounds.origin.x / containerLayer.bounds.width
}
注意: 我不是CoreAnimation的专家。这只是我从阅读您提供的文档中所理解的。
苹果在这里混合了坐标系,这造成了一些混淆。
示例图中的 x(t)
表示沿某条路径的标量进展,而不是物理坐标。
CAMediaTimingFunction 中使用的控制点用于描述此进度,而不是几何点。为了增加混淆,在控制点中,x
实际上映射到绘图中的 t
,而 y
则映射到绘图中的 x(t)
。
以 kCAMediaTimingFunctionEaseInEaseOut
的绘图为例,该绘图大致由控制点 (0,0), (0.5,0), (0.5,1), (1,1) 描述。
最好的提示可能是 WebKit 源代码中的 UnitBezier.h。实际上,我猜 Apple 在 Core Animation 中使用相同的代码。
更详细地说,他们使用计算参数 t
(与时间无关)给定值 x
,该值实际上包含时间值。然后他们使用 Newton-Raphson 方法(附加说明和示例)。由于它可能失败,他们会多次迭代到使用二分法(“分而治之”)。请参见 solveCurveX()
方法。
在获取参数 t
(这是必要的,因为三次贝塞尔曲线是参数定义的)之后,他们只需使用它来计算 y
。请参见 solve()
方法。
顺便说一句,我是 Cappuccino 的忠实粉丝,仍然希望 Atlas 能够发布 :-)
2020年1月更新:我在2012年实现Core Animation APIs时完成了这项工作。随意参考。