Equation for time-versus-position graph for iOS 7 spring animation (animateWithDuration:delay:usingSpringWithDamping:...)
Asked Answered
A

3

5

Given the spring parameters used in [UIView animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:]:

  1. usingSpringWithDamping
  2. initialSpringVelocity

what is the mathematical equation for the time-versus-position graph?

(I'm trying to get a handle on the new spring animation API in iOS 7, but I'm not getting good results, and experimentation is taking too long. My goal is to get as close as possible to some animation curve that I would have specified using CAMediaTimingFunction if I were to use Core Animation instead of UIView's block-object animation.)

Aceto answered 3/12, 2013 at 11:20 Comment(0)
B
8

DampingRatio

The damping ratio for the spring animation as it approaches its quiescent state.

To smoothly decelerate the animation without oscillation, use a value of 1. Employ a damping ratio closer to zero to increase oscillation.

As the damping value approaches 0.0 the spring becomes more bouncy.

Velocity

The initial spring velocity. For smooth start to the animation, match this value to the view’s velocity as it was prior to attachment.

A value of 1.0 for an initial spring velocity corresponds to the total animation distance traversed in one second. For example, if the total animation distance is 200 points and you want the start of the animation to match a view velocity of 100 pt/s, use a value of 0.5.

Example:

[UIView animateWithDuration:2.0
                      delay:0.0
     usingSpringWithDamping:0.4
      initialSpringVelocity:0.5
                    options:(UIViewAnimationOptions)options
                 animations:^{

                 }
                completion:nil];

enter image description here

Bean answered 10/6, 2015 at 8:59 Comment(1)
Much more helpful than the first answer.Bunsen
H
1

I believe the resulting mathematical equation is the one described here: http://en.wikipedia.org/wiki/Damping

The damping argument corresponds to damping ratio ζ, and ζ = 1 results in so-called critically damped spring that converges to final position as fast as possible without oscillating. With zero initial velocity it corresponds to something like the ease-in-ease-out curve, but with more steep ease-in part and smoother ease-out part.

For damping ratio greater than one the animation will look more linear. For damping ratio less than one oscillation around the final position will appear. Its frequency can be derived from animation duration and probably other arguments.

Here is what the docs say about the initial velocity, which should be pretty clear:

The initial spring velocity. For smooth start to the animation, match this value to the view’s velocity as it was prior to attachment. A value of 1 corresponds to the total animation distance traversed in one second. For example, if the total animation distance is 200 points and you want the start of the animation to match a view velocity of 100 pt/s, use a value of 0.5.

Hambley answered 26/2, 2014 at 10:42 Comment(0)
V
1

There are mainly four kinds of spring APIs in iOS:

  • SwiftUI Animation.spring(response:dampingFraction:blendDuration:)
  • SwiftUI Animation.interpolatingSpring(mass:stiffness:damping:initialVelocity:)
  • UIView.animate(withDuration: delay: usingSpringWithDamping: initialSpringVelocity: options: animations: completion:)
  • CASpringAnimation (with 4 physical properties: mass, stiffness, damping, initialVelocity)

They are based on the same physical process thus have the same base equation, which can be written as

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
}

There are three parameters: initialVelocity, dampingRatio and omega. dampingRatio determines the shape of the curve, when dampingRatio is 0 it is undamped harmonic oscillator, larger dampingRatio means larger friction. Using SwiftUI Animation.spring, you can have a dampingRatio that is greater than 1, using the other three APIs you can't. omega is the angular frequency if there is no damping, larger omega means quicker oscillation.

t is time in seconds. The return value of this function is relative: 0 means the starting point of the animation and 1 means the end point of the animation. initialVelocity is also relative. A value of 1 corresponds to the total animation distance traversed in one second.

Four different APIs have different ways to determine the three parameters.

(1) In Animation.spring API,

omega = 2 * π / response,

initialVelocity = 0,

dampingRatio is just dampingFraction.

(2) In Animation.interpolatingSpring API,

omega = sqrt(stiffness / mass),

dampingRatio = min(1.0, damping / 2 / sqrt(stiffness * mass))

(3) In UIView.animate API, dampingRatio and initialVelocity is just in the API's parameter, but dampingRatio is not allowed to be greater than 1. omega is calculated from the duration parameter. If dampingRatio == 1, omega is the value such that

abs(-1 + (v0 - omega) * duration) * exp(-omega * duration) == 0.001.

If dampingRatio < 1, omega is the value such that

abs(c2) * exp(a * t) == 0.001,

where c2 and a are defined in curveFunc shown above.

(4) CASpringAnimation is the same as (2).

I've written a project github.com/CosynPa/RevealSpringAnimation to mimic system spring animations. Check it out if you'd like to see more details.

Vogele answered 27/2, 2021 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.