美文网首页初见
在iOS开发中使用friction和tension的弹性动效

在iOS开发中使用friction和tension的弹性动效

作者: iDeveloper | 来源:发表于2020-06-11 10:50 被阅读0次

    在iOS系统弹性动效的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));
    

    参数为duration(时长),dampingRatio(弹性系数),velocity (初始速度);
    并没有friction(摩擦力),tension(拉力),mass(质量)参数。

    如何将friction,tension转化为duration,dampingRatio,velocity呢?

    在著名App动效设计软件Framer的开源库Framer的开源库,找到以下转换代码(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
    

    简化并转化为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动效

    设计输出的pixate文件的动效可以直接方便在iOS上编码实现。

    相关文章

      网友评论

        本文标题:在iOS开发中使用friction和tension的弹性动效

        本文链接:https://www.haomeiwen.com/subject/pzmqmctx.html