iOS中主要有四种spring API:
- SwiftUI Animation.spring(response:dampingFraction:blendDuration:)
- SwiftUI Animation.interpolatingSpring(质量:刚度:阻尼:初始速度:)
- UIView.animate(withDuration:延迟:usingSpringWithDamping:initialSpringVelocity:选项:动画:完成:)
- CASpringAnimation(具有 4 个物理属性:质量、刚度、阻尼、初始速度)
它们基于相同的物理过程,因此具有相同的基本方程,可以写为
func curveFunc(_ t: Double) -> Double {
let v0 = initialVelocity
let zeta = dampingRatio
let y: Double
if abs(zeta - 1.0) < 1e-8 {
let c1 = -1.0
let c2 = v0 - omega
y = (c1 + c2 * t) * exp(-omega * t)
} else if zeta > 1 {
let s1 = omega * (-zeta + sqrt(zeta * zeta - 1))
let s2 = omega * (-zeta - sqrt(zeta * zeta - 1))
let c1 = (-s2 - v0) / (s2 - s1)
let c2 = (s1 + v0) / (s2 - s1)
y = c1 * exp(s1 * t) + c2 * exp(s2 * t)
} else {
let a = -omega * zeta
let b = omega * sqrt(1 - zeta * zeta)
let c2 = (v0 + a) / b
let theta = atan(c2)
// Alternatively y = (-cos(b * t) + c2 * sin(b * t)) * exp(a * t)
y = sqrt(1 + c2 * c2) * exp(a * t) * cos(b * t + theta + Double.pi)
}
return y + 1
}
共有三个参数initialVelocity
:dampingRatio
和omega
。dampingRatio
决定曲线的形状,dampingRatio
为0时为无阻尼谐振子,越大dampingRatio
表示摩擦力越大。使用 SwiftUI Animation.spring,你可以拥有dampingRatio
大于 1 的 a,而使用其他三个你不能的 API。omega
是没有阻尼时的角频率,越大omega
意味着振荡越快。
t
是以秒为单位的时间。该函数的返回值是相对的:0表示动画的起点,1表示动画的终点。initialVelocity
也是相对的。值 1 对应于一秒内遍历的总动画距离。
四种不同的 API 有不同的方法来确定这三个参数。
(1) 在 Animation.spring API 中,
欧米茄 = 2 * π / 响应,
初始速度 = 0,
阻尼比只是阻尼分数。
(2) 在 Animation.interpolatingSpring API 中,
omega = sqrt(刚度/质量),
阻尼比 = min(1.0, 阻尼 / 2 / sqrt(刚度 * 质量))
(3)在UIView.animate API中,dampingRatio
只是initialVelocity
在API的参数中,但dampingRatio
不允许大于1。是从参数omega
中计算出来的。duration
如果dampingRatio == 1,omega
是这样的值
abs(-1 + (v0 - omega) * 持续时间) * exp(-omega * 持续时间) == 0.001。
如果dampingRatio < 1,omega
是这样的值
abs(c2) * exp(a * t) == 0.001,
其中c2
和a
定义curveFunc
如上所示。
(4) CASpringAnimation 同(2)。
我编写了一个项目github.com/CosynPa/RevealSpringAnimation来模拟系统弹簧动画。如果您想查看更多详细信息,请查看它。