• 支持xcode6的缓动函数Easing以及使用示例


    支持xcode6的缓动函数Easing以及使用示例

    用xcode6新建工程后,直接导致不支持之前的Easing缓动函数的代码,经过修改后就可以正常使用了,虽然比不上POP高大上的动画,但用缓动函数的动画还是能够实现很复杂的效果的。

    注:Easing缓动函数服务于关键帧动画,理解这一点很重要,需要你对CoreAnimation有着很深入的了解才能够用得得心应手

    提供源码如下:

    Easing.h 与 Easing.m

    //
    //  Easing.h
    //  Easing
    //
    //  Created by YouXianMing on 14-10-10.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #ifndef __Easing__Easing__
    #define __Easing__Easing__
    
    #include <stdio.h>
    #include <math.h>
    
    #if defined(__LP64__) && !defined(AH_EASING_USE_DBL_PRECIS)
    #define AH_EASING_USE_DBL_PRECIS
    #endif
    
    #ifdef AH_EASING_USE_DBL_PRECIS
    #define AHFloat double
    #else
    #define AHFloat float
    #endif
    
    // 函数指针
    typedef AHFloat (*AHEasingFunction)(AHFloat);
    
    // Linear interpolation (no easing)
    AHFloat LinearInterpolation(AHFloat p);
    
    // Quadratic easing; p^2
    AHFloat QuadraticEaseIn(AHFloat p);
    AHFloat QuadraticEaseOut(AHFloat p);
    AHFloat QuadraticEaseInOut(AHFloat p);
    
    // Cubic easing; p^3
    AHFloat CubicEaseIn(AHFloat p);
    AHFloat CubicEaseOut(AHFloat p);
    AHFloat CubicEaseInOut(AHFloat p);
    
    // Quartic easing; p^4
    AHFloat QuarticEaseIn(AHFloat p);
    AHFloat QuarticEaseOut(AHFloat p);
    AHFloat QuarticEaseInOut(AHFloat p);
    
    // Quintic easing; p^5
    AHFloat QuinticEaseIn(AHFloat p);
    AHFloat QuinticEaseOut(AHFloat p);
    AHFloat QuinticEaseInOut(AHFloat p);
    
    // Sine wave easing; sin(p * PI/2)
    AHFloat SineEaseIn(AHFloat p);
    AHFloat SineEaseOut(AHFloat p);
    AHFloat SineEaseInOut(AHFloat p);
    
    // Circular easing; sqrt(1 - p^2)
    AHFloat CircularEaseIn(AHFloat p);
    AHFloat CircularEaseOut(AHFloat p);
    AHFloat CircularEaseInOut(AHFloat p);
    
    // Exponential easing, base 2
    AHFloat ExponentialEaseIn(AHFloat p);
    AHFloat ExponentialEaseOut(AHFloat p);
    AHFloat ExponentialEaseInOut(AHFloat p);
    
    // Exponentially-damped sine wave easing
    AHFloat ElasticEaseIn(AHFloat p);
    AHFloat ElasticEaseOut(AHFloat p);
    AHFloat ElasticEaseInOut(AHFloat p);
    
    // Overshooting cubic easing;
    AHFloat BackEaseIn(AHFloat p);
    AHFloat BackEaseOut(AHFloat p);
    AHFloat BackEaseInOut(AHFloat p);
    
    // Exponentially-decaying bounce easing
    AHFloat BounceEaseIn(AHFloat p);
    AHFloat BounceEaseOut(AHFloat p);
    AHFloat BounceEaseInOut(AHFloat p);
    
    
    
    #endif /* defined(__Easing__Easing__) */
    //
    //  Easing.c
    //  Easing
    //
    //  Created by YouXianMing on 14-10-10.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #include "Easing.h"
    
    // Modeled after the line y = x
    AHFloat LinearInterpolation(AHFloat p)
    {
        return p;
    }
    
    // Modeled after the parabola y = x^2
    AHFloat QuadraticEaseIn(AHFloat p)
    {
        return p * p;
    }
    
    // Modeled after the parabola y = -x^2 + 2x
    AHFloat QuadraticEaseOut(AHFloat p)
    {
        return -(p * (p - 2));
    }
    
    // Modeled after the piecewise quadratic
    // y = (1/2)((2x)^2)             ; [0, 0.5)
    // y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1]
    AHFloat QuadraticEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 2 * p * p;
        }
        else
        {
            return (-2 * p * p) + (4 * p) - 1;
        }
    }
    
    // Modeled after the cubic y = x^3
    AHFloat CubicEaseIn(AHFloat p)
    {
        return p * p * p;
    }
    
    // Modeled after the cubic y = (x - 1)^3 + 1
    AHFloat CubicEaseOut(AHFloat p)
    {
        AHFloat f = (p - 1);
        return f * f * f + 1;
    }
    
    // Modeled after the piecewise cubic
    // y = (1/2)((2x)^3)       ; [0, 0.5)
    // y = (1/2)((2x-2)^3 + 2) ; [0.5, 1]
    AHFloat CubicEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 4 * p * p * p;
        }
        else
        {
            AHFloat f = ((2 * p) - 2);
            return 0.5 * f * f * f + 1;
        }
    }
    
    // Modeled after the quartic x^4
    AHFloat QuarticEaseIn(AHFloat p)
    {
        return p * p * p * p;
    }
    
    // Modeled after the quartic y = 1 - (x - 1)^4
    AHFloat QuarticEaseOut(AHFloat p)
    {
        AHFloat f = (p - 1);
        return f * f * f * (1 - p) + 1;
    }
    
    // Modeled after the piecewise quartic
    // y = (1/2)((2x)^4)        ; [0, 0.5)
    // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1]
    AHFloat QuarticEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 8 * p * p * p * p;
        }
        else
        {
            AHFloat f = (p - 1);
            return -8 * f * f * f * f + 1;
        }
    }
    
    // Modeled after the quintic y = x^5
    AHFloat QuinticEaseIn(AHFloat p)
    {
        return p * p * p * p * p;
    }
    
    // Modeled after the quintic y = (x - 1)^5 + 1
    AHFloat QuinticEaseOut(AHFloat p)
    {
        AHFloat f = (p - 1);
        return f * f * f * f * f + 1;
    }
    
    // Modeled after the piecewise quintic
    // y = (1/2)((2x)^5)       ; [0, 0.5)
    // y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]
    AHFloat QuinticEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 16 * p * p * p * p * p;
        }
        else
        {
            AHFloat f = ((2 * p) - 2);
            return  0.5 * f * f * f * f * f + 1;
        }
    }
    
    // Modeled after quarter-cycle of sine wave
    AHFloat SineEaseIn(AHFloat p)
    {
        return sin((p - 1) * M_PI_2) + 1;
    }
    
    // Modeled after quarter-cycle of sine wave (different phase)
    AHFloat SineEaseOut(AHFloat p)
    {
        return sin(p * M_PI_2);
    }
    
    // Modeled after half sine wave
    AHFloat SineEaseInOut(AHFloat p)
    {
        return 0.5 * (1 - cos(p * M_PI));
    }
    
    // Modeled after shifted quadrant IV of unit circle
    AHFloat CircularEaseIn(AHFloat p)
    {
        return 1 - sqrt(1 - (p * p));
    }
    
    // Modeled after shifted quadrant II of unit circle
    AHFloat CircularEaseOut(AHFloat p)
    {
        return sqrt((2 - p) * p);
    }
    
    // Modeled after the piecewise circular function
    // y = (1/2)(1 - sqrt(1 - 4x^2))           ; [0, 0.5)
    // y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]
    AHFloat CircularEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 0.5 * (1 - sqrt(1 - 4 * (p * p)));
        }
        else
        {
            return 0.5 * (sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1);
        }
    }
    
    // Modeled after the exponential function y = 2^(10(x - 1))
    AHFloat ExponentialEaseIn(AHFloat p)
    {
        return (p == 0.0) ? p : pow(2, 10 * (p - 1));
    }
    
    // Modeled after the exponential function y = -2^(-10x) + 1
    AHFloat ExponentialEaseOut(AHFloat p)
    {
        return (p == 1.0) ? p : 1 - pow(2, -10 * p);
    }
    
    // Modeled after the piecewise exponential
    // y = (1/2)2^(10(2x - 1))         ; [0,0.5)
    // y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]
    AHFloat ExponentialEaseInOut(AHFloat p)
    {
        if(p == 0.0 || p == 1.0) return p;
        
        if(p < 0.5)
        {
            return 0.5 * pow(2, (20 * p) - 10);
        }
        else
        {
            return -0.5 * pow(2, (-20 * p) + 10) + 1;
        }
    }
    
    // Modeled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))
    AHFloat ElasticEaseIn(AHFloat p)
    {
        return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1));
    }
    
    // Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1
    AHFloat ElasticEaseOut(AHFloat p)
    {
        return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1;
    }
    
    // Modeled after the piecewise exponentially-damped sine wave:
    // y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1))      ; [0,0.5)
    // y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2) ; [0.5, 1]
    AHFloat ElasticEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 0.5 * sin(13 * M_PI_2 * (2 * p)) * pow(2, 10 * ((2 * p) - 1));
        }
        else
        {
            return 0.5 * (sin(-13 * M_PI_2 * ((2 * p - 1) + 1)) * pow(2, -10 * (2 * p - 1)) + 2);
        }
    }
    
    // Modeled after the overshooting cubic y = x^3-x*sin(x*pi)
    AHFloat BackEaseIn(AHFloat p)
    {
        return p * p * p - p * sin(p * M_PI);
    }
    
    // Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi))
    AHFloat BackEaseOut(AHFloat p)
    {
        AHFloat f = (1 - p);
        return 1 - (f * f * f - f * sin(f * M_PI));
    }
    
    // Modeled after the piecewise overshooting cubic function:
    // y = (1/2)*((2x)^3-(2x)*sin(2*x*pi))           ; [0, 0.5)
    // y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1]
    AHFloat BackEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            AHFloat f = 2 * p;
            return 0.5 * (f * f * f - f * sin(f * M_PI));
        }
        else
        {
            AHFloat f = (1 - (2*p - 1));
            return 0.5 * (1 - (f * f * f - f * sin(f * M_PI))) + 0.5;
        }
    }
    
    AHFloat BounceEaseIn(AHFloat p)
    {
        return 1 - BounceEaseOut(1 - p);
    }
    
    AHFloat BounceEaseOut(AHFloat p)
    {
        if(p < 4/11.0)
        {
            return (121 * p * p)/16.0;
        }
        else if(p < 8/11.0)
        {
            return (363/40.0 * p * p) - (99/10.0 * p) + 17/5.0;
        }
        else if(p < 9/10.0)
        {
            return (4356/361.0 * p * p) - (35442/1805.0 * p) + 16061/1805.0;
        }
        else
        {
            return (54/5.0 * p * p) - (513/25.0 * p) + 268/25.0;
        }
    }
    
    AHFloat BounceEaseInOut(AHFloat p)
    {
        if(p < 0.5)
        {
            return 0.5 * BounceEaseIn(p*2);
        }
        else
        {
            return 0.5 * BounceEaseOut(p * 2 - 1) + 0.5;
        }
    }

    进一步封装的面向对象的使用代码

    YXEasing.m 与 YXEasing.h

    //
    //  YXEasing.h
    //  Prize
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    #import "Easing.h"
    
    /*---------------------------------------------
    
     -动画简单的解析-
     
     BackEase        :在某一动画开始沿指示的路径进行动画处理前稍稍收回该动画的移动。
     BounceEase      :创建弹跳效果。
     CircleEase      :创建使用循环函数加速和/或减速的动画。
     CubicEase       :创建使用公式 f(t) = t^3 加速和/或减速的动画。
     ElasticEase     :创建类似于弹簧在停止前来回振荡的动画。
     ExponentialEase :创建使用指数公式加速和/或减速的动画。
     PowerEase       :创建使用公式 f(t) = t^p(其中,p 等于 Power 属性)加速和/或减速的动画。
     QuadraticEase   :创建使用公式 f(t) = t^2 加速和/或减速的动画。
     QuarticEase     :创建使用公式 f(t) = t^4 加速和/或减速的动画。
     QuinticEase     :创建使用公式 f(t) = t^5 加速和/或减速的动画。
     SineEase        :创建使用正弦公式加速和/或减速的动画。
     
    LinearInterpolation
    
    QuadraticEaseIn
    QuadraticEaseOut
    QuadraticEaseInOut
    
    CubicEaseIn
    CubicEaseOut
    CubicEaseInOut
    
    QuarticEaseIn
    QuarticEaseOut
    QuarticEaseInOut
    
    QuinticEaseIn
    QuinticEaseOut
    QuinticEaseInOut
    
    SineEaseIn
    SineEaseOut
    SineEaseInOut
    
    CircularEaseIn
    CircularEaseOut
    CircularEaseInOut
    
    ExponentialEaseIn
    ExponentialEaseOut
    ExponentialEaseInOut
    
    ElasticEaseIn
    ElasticEaseOut
    ElasticEaseInOut
    
    BackEaseIn
    BackEaseOut
    BackEaseInOut
    
    BounceEaseIn
    BounceEaseOut
    BounceEaseInOut
    ---------------------------------------------*/
    
    /*
     // 计算好起始值,结束值
     CGFloat oldValue = 0.f;
     CGFloat newValue = 1.f;
     
     // 关键帧动画
     CAKeyframeAnimation *animation = 
     [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
     
     // 设置值
     [animation setValues:[YXEasing calculateFrameFromValue:oldValue
     toValue:newValue
     func:ElasticEaseOut
     frameCount:500]];
     
     // 设置持续时间
     animation.duration  = 0.5f;
     
     // 每秒增加的角度(设定结果值,在提交动画之前执行)
     layer.transform = 
     CATransform3DMakeRotation(newValue, 0.0, 0.0, 1.0);
     
     // 提交动画
     [layer addAnimation:animation forKey:nil];
     
     */
    
    @interface YXEasing : NSObject
    
    // 数组中存储的数据为 NSNumber float 型
    + (NSArray *)calculateFrameFromValue:(CGFloat)fromValue
                                 toValue:(CGFloat)toValue
                                    func:(AHEasingFunction)func
                              frameCount:(size_t)frameCount;
    
    // 数组中存储的数据为 NSValue CGPoint 型
    + (NSArray *)calculateFrameFromPoint:(CGPoint)fromPoint
                                 toPoint:(CGPoint)toPoint
                                    func:(AHEasingFunction)func
                              frameCount:(size_t)frameCount;
    
    // 数组中存储的数据为 NSValue CGSize 型
    + (NSArray *)calculateFrameFromSize:(CGSize)fromSize
                                 toSize:(CGSize)toSize
                                   func:(AHEasingFunction)func
                             frameCount:(size_t)frameCount;
    
    @end
    //
    //  YXEasing.m
    //  Prize
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import "YXEasing.h"
    
    @implementation YXEasing
    
    + (NSArray *)calculateFrameFromValue:(CGFloat)fromValue
                                 toValue:(CGFloat)toValue
                                    func:(AHEasingFunction)func
                              frameCount:(size_t)frameCount
    {
        // 设置帧数量
        NSMutableArray *values = [NSMutableArray arrayWithCapacity:frameCount];
        
        // 计算并存储
        CGFloat t = 0.0;
        CGFloat dt = 1.0 / (frameCount - 1);
        for(size_t frame = 0; frame < frameCount; ++frame, t += dt)
        {
            // 此处就会根据不同的函数计算出不同的值达到不同的效果
            CGFloat value = fromValue + func(t) * (toValue - fromValue);
            
            // 将计算结果存储进数组中
            [values addObject:[NSNumber numberWithFloat:(float)value]];
        }
        
        // 数组中存储的数据为 NSNumber float 型
        return values;
    }
    
    + (NSArray *)calculateFrameFromPoint:(CGPoint)fromPoint
                                 toPoint:(CGPoint)toPoint
                                    func:(AHEasingFunction)func
                              frameCount:(size_t)frameCount
    {
        // 设置帧数量
        NSMutableArray *values = [NSMutableArray arrayWithCapacity:frameCount];
        
        // 计算并存储
        CGFloat t = 0.0;
        CGFloat dt = 1.0 / (frameCount - 1);
        for(size_t frame = 0; frame < frameCount; ++frame, t += dt)
        {
            // 此处就会根据不同的函数计算出不同的值达到不同的效果
            CGFloat x = fromPoint.x + func(t) * (toPoint.x - fromPoint.x);
            CGFloat y = fromPoint.y + func(t) * (toPoint.y - fromPoint.y);
            
            // 将计算结果存储进数组中
            [values addObject:[NSValue valueWithCGPoint:CGPointMake(x, y)]];
        }
        
        // 数组中存储的数据为 NSValue CGPoint 型
        return values;
    }
    
    + (NSArray *)calculateFrameFromSize:(CGSize)fromSize
                                 toSize:(CGSize)toSize
                                   func:(AHEasingFunction)func
                             frameCount:(size_t)frameCount
    {
        // 设置帧数量
        NSMutableArray *values = [NSMutableArray arrayWithCapacity:frameCount];
        
        // 计算并存储
        CGFloat t = 0.0;
        CGFloat dt = 1.0 / (frameCount - 1);
        for(size_t frame = 0; frame < frameCount; ++frame, t += dt)
        {
            // 此处就会根据不同的函数计算出不同的值达到不同的效果
            CGFloat w = fromSize.width + func(t) * (toSize.width - fromSize.width);
            CGFloat h = fromSize.height + func(t) * (toSize.height - fromSize.height);
    
            // 将计算结果存储进数组中
            [values addObject:[NSValue valueWithCGSize:CGSizeMake(w, h)]];
        }
        
        // 数组中存储的数据为 NSValue CGSize 型
        return values;
    }
    
    @end

    使用示例:

    //
    //  ViewController.m
    //  Easing
    //
    //  Created by YouXianMing on 14-10-10.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #import "ViewController.h"
    #import "YXEasing.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
     
        UIView *showView         = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
        showView.backgroundColor = [UIColor redColor];
        showView.center          = self.view.center;
        [self.view addSubview:showView];
        
        // 计算好起始值,结束值
        CGFloat oldValue = 0.f;
        CGFloat newValue = 1.f;
        
        // 关键帧动画
        CAKeyframeAnimation *animation = 
            [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
        
        // 设置值
        [animation setValues:[YXEasing calculateFrameFromValue:oldValue
                                                       toValue:newValue
                                                          func:ElasticEaseOut
                                                    frameCount:500]];
        
        // 设置持续时间
        animation.duration  = 1.5f;
    
        // 每秒增加的角度(设定结果值,在提交动画之前执行)
        showView.layer.transform = 
            CATransform3DMakeRotation(newValue, 0.0, 0.0, 1.0);
        
        // 提交动画
        [showView.layer addAnimation:animation forKey:nil];
        
    
    }
    
    @end

    效果如下图:

  • 相关阅读:
    react 性能优化
    JS获取当前网页大小以及屏幕分辨率等
    创建对象的6种方式总结
    版本号规则
    JS事件模型
    浅谈虚拟DOM
    浏览器的回流与重绘
    JavaScript预编译
    canvas学习笔记
    java、tomcat安装
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/4015556.html
Copyright © 2020-2023  润新知