Определить springWithDamping и initialSpringVelocity на основе трения и растяжения - PullRequest
0 голосов
/ 25 апреля 2018

Моя команда дизайнеров дает нам параметры анимации, используя трение и растяжение.Например:

Влияет на пружину (растяжение 280 и трение 20,5). За 0,3 секунды

К сожалению, я всегда догадывался, во что преобразуются эти значения, и в глазное яблоко.это, если это выглядит близко, я посылаю это, и они одобряют это.Но время, необходимое для постоянного построения проекта с разными значениями, отнимает много времени.Должен быть более легкий путь.

Я нашел Framer на Github, и это заставило меня поверить, что демпфирование можно рассчитать так:

let damping: CGFloat = 20.5 / (2 * (1 * 280)).squareRoot()

Однако я не могу понять, какрассчитать скорость исходя из трения и растяжения.Есть ли более простой способ сэкономить этому разработчику немного драгоценного времени?

Пример анимации:

UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: damping,
                       initialSpringVelocity: ???, options: .curveEaseIn, animations: { // Do Stuff })

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Я перевел код @Niels на Swift.

import UIKit

func computeDuration(tension: Double, friction: Double, velocity: Double = 0.0, mass: Double = 1.0) -> Double {
    let dampingRatio = computeDampingRatio(tension: tension, friction: friction)
    let undampedFrequency = sqrt(tension / mass)

    let epsilon = 0.001
    var duration = 0.0

    //This is basically duration extracted out of the envelope functions
    if dampingRatio < 1 {
        let a = sqrt(1 - pow(dampingRatio, 2))
        let b = velocity / (a * undampedFrequency)
        let c = dampingRatio / a
        let d = -((b - c) / epsilon)
        if d <= 0 {
            return duration
        }

        duration = log(d) / (dampingRatio * undampedFrequency)
    }

    return duration
}

func computeDampingRatio(tension: Double, friction: Double) -> Double {
    let damping = friction / sqrt(2 * (1 * tension))
    return damping
}
0 голосов
/ 03 мая 2019

Я преобразовал это в удобное расширение UIView, чтобы вы могли просто вызывать UIView.animate непосредственно с натяжением и трением.

extension UIView {
    class func animate(withTension tension: CGFloat, friction: CGFloat, mass: CGFloat = 1.0, delay: TimeInterval = 0, initialSpringVelocity velocity: CGFloat = 0, options: UIView.AnimationOptions = [], animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
        let damping = friction / sqrt(2 * (1 * tension))
        let undampedFrequency = sqrt(tension / mass)

        let epsilon: CGFloat = 0.001
        var duration: TimeInterval = 0

        if damping < 1 {
            let a = sqrt(1 - pow(damping, 2))
            let b = velocity / (a * undampedFrequency)
            let c = damping / a
            let d = -((b - c) / epsilon)
            if d > 0 {
                duration = TimeInterval(log(d) / (damping * undampedFrequency))
            }
        }

        UIView.animate(withDuration: duration, delay: delay, usingSpringWithDamping: damping, initialSpringVelocity: velocity, options: options, animations: animations, completion: completion)
    }
}
0 голосов
/ 29 апреля 2018

Вы правы, что код, на который вы ссылались, может быть использован для вычисления коэффициента демпфирования (я польщен, потому что я тот, кто его написал;).Похоже, у вас есть ошибка в вашем производном коде Swift.Я думаю, что это должно быть (обратите внимание на разницу в скобках):

let damping: CGFloat = 20.5 / (2 * (1 * 280).squareRoot())

Значение скорости необходимо только в том случае, если вы хотите дать объекту некоторую начальную скорость при запуске анимации.Вариант использования для этого - если объект уже движется при запуске анимации (например, при запуске анимации после взаимодействия с перетаскиванием).

Таким образом, если объект начинает анимацию из неподвижного состояния, вы можетепросто используйте 0 в качестве начальной скорости.

Меня смущает ваша команда дизайнеров, дающая вам напряжение, трение и длительность .Поскольку пружины симулируют физику, натяжение и трение будут симулировать пружину, которая прекратит анимацию через определенное время.Пружина с натяжением 280 и трением 20.5 приводит к продолжительности, близкой к 0.65, а не 0.3.(см. функцию computeDuration во Фреймере, как рассчитать длительность по напряжению и трению).Вот версия coffeescript:

# 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

Причина, по которой вы можете указать продолжительность для пружин, используемых iOS, заключается в том, что она рассчитывает натяжение и трение пружины на основе коэффициента демпфирования и продолжительности.Под капотом он все равно будет использовать натяжение и трение для симуляции пружины.Чтобы получить представление о том, как этот код работает в iOS, посмотрите на computeDerivedCurveOptions во Framer, который является прямым портом кода, используемого iOS (созданный путем разборки и анализа двоичных файлов iOS).

...