Skip to content

Instantly share code, notes, and snippets.

# edwardsanchez/SpringAnimator.swift Last active Jun 17, 2019

Spring Animator
 //: Playground - noun: a place where people can play import UIKit //Changing values var initialVelocity: CGFloat = 0 var runningTime: CGFloat = 0 var myProperty: CGFloat = 0 //Resting position of spring let endNumberValue: CGFloat = 300 //Set relaxation time (duration in seconds) let relaxationTime: CGFloat = 1 //Spring constants let dampingRatio: CGFloat = 0.9 //Only allow damping ratio between just above 0 and 1 (critically damped) let clippedDampingRatio: CGFloat = min(1, max(dampingRatio, 0.01)) let mass: CGFloat = 1 let fractionOfAmplitude: CGFloat = 1500 //A spring never gets to 0 amplitude, it gets infinitely smaller. This fraction represents the perceived 0 point. let logOfFraction: CGFloat = log(fractionOfAmplitude) let stiffness: CGFloat = (mass * pow(logOfFraction, 2)) / (pow(relaxationTime, 2) * pow(clippedDampingRatio, 2)) let angularFrequency: CGFloat = sqrt(stiffness/mass) let damping: CGFloat = 2 * mass * angularFrequency * clippedDampingRatio internal func springFunction(_ currentValue: CGFloat, _ length: CGFloat, _ velocity: inout CGFloat) -> CGFloat { let displacement = currentValue - length let springForce = -stiffness * displacement // Hooke's Law (F = -kx) (where k is stiffness constant and x is displacement value) let forceDamper = -damping * velocity // F = -dv (where d is damping constant and v is velocity) let dampedForce = springForce + forceDamper let acceleration = dampedForce / mass // a = F / m let refreshRate: CGFloat = 1/60 //Hz velocity += acceleration * refreshRate let position = velocity * refreshRate return position } public func animateProperty(_ property: inout CGFloat, _ runningTime: CGFloat) { if runningTime < relaxationTime { property += springFunction(property, endNumberValue, &initialVelocity) } else { //Set final value to exact value property = endNumberValue } } while runningTime <= relaxationTime { //Put this inside a CADisplayLink updating the running time and your view origin will animate in a spring animateProperty(&myProperty, runningTime) runningTime += 1/60 print(myProperty) }
to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
{"ft_lang_label":"__label__en","ft_lang_prob":0.586489,"math_prob":0.9855324,"size":2125,"snap":"2019-35-2019-39","text_gpt3_token_len":543,"char_repetition_ratio":0.17161717,"word_repetition_ratio":0.0,"special_character_ratio":0.26164705,"punctuation_ratio":0.12374582,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.98869014,"pos_list":[0,1,2],"im_url_duplicate_count":[null,null,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2019-08-24T08:05:58Z\",\"WARC-Record-ID\":\"<urn:uuid:30a38048-7234-4868-91f1-e3ba9cee5823>\",\"Content-Length\":\"60759\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:a53fb791-7af5-4f9d-83b8-e9a98fb23d55>\",\"WARC-Concurrent-To\":\"<urn:uuid:5acf6456-51e7-49e6-9152-80a555e85f23>\",\"WARC-IP-Address\":\"192.30.253.119\",\"WARC-Target-URI\":\"https://gist.github.com/edwardsanchez/9d0a411e58d97f3f521f0bc845205f52\",\"WARC-Payload-Digest\":\"sha1:O56FKPW3Q222DOTW6GKKDDN4ZIRFYAME\",\"WARC-Block-Digest\":\"sha1:P5AKUD23CRXS5HLPEXCUPTNLHTNDDRTS\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2019/CC-MAIN-2019-35/CC-MAIN-2019-35_segments_1566027319915.98_warc_CC-MAIN-20190824063359-20190824085359-00059.warc.gz\"}"}