在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];
}
設(shè)計輸出的pixate文件的動效可以直接方便在iOS上編碼實現(xiàn)淑趾。