在iOS開發(fā)中使用friction和tension的彈性動效

在iOS系統(tǒng)彈性動效的API接口

+ (void)animateWithDuration:(NSTimeInterval)duration
                      delay:(NSTimeInterval)delay
     usingSpringWithDamping:(CGFloat)dampingRatio
      initialSpringVelocity:(CGFloat)velocity
                    options:(UIViewAnimationOptions)options
                 animations:(void (^)(void))animations
                 completion:(void (^ __nullable)(BOOL finished))completion API_AVAILABLE(ios(7.0));

參數(shù)為duration(時長)诫肠,dampingRatio(彈性系數(shù))躁锡,velocity (初始速度)煤伟;
并沒有friction(摩擦力)瞭吃,tension(拉力)恐似,mass(質(zhì)量)參數(shù)杜跷。

如何將friction,tension轉(zhuǎn)化為duration,dampingRatio葛闷,velocity呢憋槐?

在著名App動效設(shè)計軟件Framer的開源庫Framer的開源庫,找到以下轉(zhuǎn)換代碼(CoffeeScript):

epsilon =  0.001
minDuration = 0.01
maxDuration = 10.0
minDamping = Number.MIN_VALUE
maxDamping = 1

# Newton's method
approximateRoot = (func, derivative, initialGuess, times=12) ->
    result = initialGuess
    for i in [1...times]
        result = result - func(result) / derivative(result)
    return result

angularFrequency = (undampedFrequency, dampingRatio) ->
    undampedFrequency * Math.sqrt(1 - Math.pow(dampingRatio, 2))

exports.computeDampingRatio = computeDampingRatio = (tension, friction, mass = 1) ->
    friction / (2 * Math.sqrt(mass * tension))

# Tries to compute the duration of a spring,
# but can't for certain velocities and if dampingRatio >= 1
# In those cases it will return null
exports.computeDuration = (tension, friction, velocity = 0, mass = 1) ->
    dampingRatio = computeDampingRatio(tension, friction)
    undampedFrequency = Math.sqrt(tension / mass)
    # This is basically duration extracted out of the envelope functions
    if dampingRatio < 1
        a = Math.sqrt(1 - Math.pow(dampingRatio, 2))
        b = velocity / (a * undampedFrequency)
        c = dampingRatio / a
        d = - ((b - c) / epsilon)
        if d <= 0
            return null
        duration = Math.log(d) / (dampingRatio * undampedFrequency)
    else
        return null
    return duration

exports.computeDerivedCurveOptions = (dampingRatio, duration, velocity = 0, mass = 1) ->
    dampingRatio = Math.max(Math.min(dampingRatio, maxDamping), minDamping)
    duration = Math.max(Math.min(duration, maxDuration), minDuration)

    if dampingRatio < 1
        envelope = (undampedFrequency) ->
            exponentialDecay = undampedFrequency * dampingRatio
            currentDisplacement = exponentialDecay * duration
            a = (exponentialDecay) - velocity
            b = angularFrequency(undampedFrequency, dampingRatio)
            c = Math.exp(-currentDisplacement)
            return epsilon - (a / b) * c

        derivative = (undampedFrequency) ->
            exponentialDecay = undampedFrequency * dampingRatio
            currentDisplacement = exponentialDecay * duration
            d = currentDisplacement * velocity + velocity
            e = Math.pow(dampingRatio, 2) * Math.pow(undampedFrequency, 2) * duration
            f = Math.exp(-currentDisplacement)
            g = angularFrequency(Math.pow(undampedFrequency, 2), dampingRatio)
            factor = if (- envelope(undampedFrequency) + epsilon) > 0 then -1 else 1
            return factor * ((d - e) * f) / g
    else
        envelope = (undampedFrequency) ->
            a = Math.exp(-undampedFrequency * duration)
            b = (undampedFrequency - velocity) * duration + 1
            return -epsilon + a * b

        derivative = (undampedFrequency) ->
            a = Math.exp(-undampedFrequency * duration)
            b = (velocity - undampedFrequency) * Math.pow(duration, 2)
            return a * b

    result =
        tension: 100
        friction: 10
        velocity: velocity

    initialGuess = 5 / duration
    undampedFrequency = approximateRoot(envelope, derivative, initialGuess)
    unless isNaN(undampedFrequency)
        result.tension = Math.pow(undampedFrequency, 2) * mass
        result.friction = dampingRatio * 2 * Math.sqrt(mass * result.tension)
    return result

簡化并轉(zhuǎn)化為oc代碼后


+ (void)animateWithFriction:(CGFloat)friction
                    Tension:(CGFloat)tension
                      delay:(NSTimeInterval)delay
                 animations:(void (^)(void))animations
                 completion:(void (^ __nullable)(BOOL finished))completion {
    //初始速度默認為1
    [UIView animateWithFriction:friction
                        Tension:tension
                           mass:1
                          delay:delay
          initialSpringVelocity:0
                        options:0
                     animations:animations
                     completion:completion];
}

+ (void)animateWithFriction:(CGFloat)friction
                    Tension:(CGFloat)tension
                       mass:(CGFloat)mass
                      delay:(NSTimeInterval)delay
      initialSpringVelocity:(CGFloat)velocity
                    options:(UIViewAnimationOptions)options
                 animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion {
    CGFloat damping = friction / sqrt(2 * (1 * tension));
    CGFloat undampedFrequency = sqrt(tension / mass);
    
    CGFloat epsilon = 0.001;
    NSTimeInterval duration = 0;

    if (damping < 1) {
        CGFloat a = sqrt(1 - pow(damping, 2));
        CGFloat b = velocity / (a * undampedFrequency);
        CGFloat c = damping / a;
        CGFloat d = -((b - c) / epsilon);
        if (d > 0) {
            duration = log(d) / (damping * undampedFrequency);
        }
    }
    [UIView animateWithDuration:duration
                          delay:delay
         usingSpringWithDamping:damping
          initialSpringVelocity:velocity
                        options:options
                     animations:animations
                     completion:completion];
}
pixate動效

設(shè)計輸出的pixate文件的動效可以直接方便在iOS上編碼實現(xiàn)淑趾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阳仔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子扣泊,更是在濱河造成了極大的恐慌近范,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件延蟹,死亡現(xiàn)場離奇詭異评矩,居然都是意外死亡,警方通過查閱死者的電腦和手機阱飘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門斥杜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沥匈,你說我怎么就攤上這事蔗喂。” “怎么了咐熙?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵弱恒,是天一觀的道長。 經(jīng)常有香客問我棋恼,道長,這世上最難降的妖魔是什么锈玉? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任爪飘,我火速辦了婚禮,結(jié)果婚禮上拉背,老公的妹妹穿的比我還像新娘师崎。我一直安慰自己,他們只是感情好椅棺,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布犁罩。 她就那樣靜靜地躺著,像睡著了一般两疚。 火紅的嫁衣襯著肌膚如雪床估。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天诱渤,我揣著相機與錄音丐巫,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛递胧,可吹牛的內(nèi)容都是我干的碑韵。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼缎脾,長吁一口氣:“原來是場噩夢啊……” “哼祝闻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起遗菠,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤治筒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后舷蒲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耸袜,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年牲平,在試婚紗的時候發(fā)現(xiàn)自己被綠了堤框。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡纵柿,死狀恐怖蜈抓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情昂儒,我是刑警寧澤沟使,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站渊跋,受9級特大地震影響腊嗡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拾酝,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一燕少、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒿囤,春花似錦客们、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脸侥,卻和暖如春建邓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背湿痢。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工涝缝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扑庞,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓拒逮,卻偏偏與公主長得像罐氨,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子滩援,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348