Swift-EasingAnimation
效果
源码
https://github.com/YouXianMing/UI-Component-Collection
// // Easing.swift // Swift-EasingAnimation // // Created by YouXianMing on 15/10/21. // // https://github.com/YouXianMing // http://home.cnblogs.com/u/YouXianMing/ // import UIKit enum EasingFunction: Int { case LinearInterpolation = 1, // Quadratic easing; p^2 QuadraticEaseIn, QuadraticEaseOut, QuadraticEaseInOut, // Cubic easing; p^3 CubicEaseIn, CubicEaseOut, CubicEaseInOut, // Quartic easing; p^4 QuarticEaseIn, QuarticEaseOut, QuarticEaseInOut, // Quintic easing; p^5 QuinticEaseIn, QuinticEaseOut, QuinticEaseInOut, // Sine wave easing; sin(p * PI/2) SineEaseIn, SineEaseOut, SineEaseInOut, // Circular easing; sqrt(1 - p^2) CircularEaseIn, CircularEaseOut, CircularEaseInOut, // Exponential easing, base 2 ExponentialEaseIn, ExponentialEaseOut, ExponentialEaseInOut, // Exponentially-damped sine wave easing ElasticEaseIn, ElasticEaseOut, ElasticEaseInOut, // Overshooting cubic easing; BackEaseIn, BackEaseOut, BackEaseInOut, // Exponentially-decaying bounce easing BounceEaseIn, BounceEaseOut, BounceEaseInOut func value() -> ((Double) -> Double) { switch self { case .LinearInterpolation: return Easing.LinearInterpolation case .QuadraticEaseIn: return Easing.QuadraticEaseIn case .QuadraticEaseOut: return Easing.QuadraticEaseOut case .QuadraticEaseInOut: return Easing.QuadraticEaseInOut case .CubicEaseIn: return Easing.CubicEaseIn case .CubicEaseOut: return Easing.CubicEaseOut case .CubicEaseInOut: return Easing.CubicEaseInOut case .QuarticEaseIn: return Easing.QuarticEaseIn case .QuarticEaseOut: return Easing.QuarticEaseOut case .QuarticEaseInOut: return Easing.QuarticEaseInOut case .QuinticEaseIn: return Easing.QuinticEaseIn case .QuinticEaseOut: return Easing.QuinticEaseOut case .QuinticEaseInOut: return Easing.QuinticEaseInOut case .SineEaseIn: return Easing.SineEaseIn case .SineEaseOut: return Easing.SineEaseOut case .SineEaseInOut: return Easing.SineEaseInOut case .CircularEaseIn: return Easing.CircularEaseIn case .CircularEaseOut: return Easing.CircularEaseOut case .CircularEaseInOut: return Easing.CircularEaseInOut case .ExponentialEaseIn: return Easing.ExponentialEaseIn case .ExponentialEaseOut: return Easing.ExponentialEaseOut case .ExponentialEaseInOut: return Easing.ExponentialEaseInOut case .ElasticEaseIn: return Easing.ElasticEaseIn case .ElasticEaseOut: return Easing.ElasticEaseOut case .ElasticEaseInOut: return Easing.ElasticEaseInOut case .BackEaseIn: return Easing.BackEaseIn case .BackEaseOut: return Easing.BackEaseOut case .BackEaseInOut: return Easing.BackEaseInOut case .BounceEaseIn: return Easing.BounceEaseIn case .BounceEaseOut: return Easing.BounceEaseOut case .BounceEaseInOut: return Easing.BounceEaseInOut } } } class Easing: NSObject { // MARK: Linear interpolation (no easing) class func LinearInterpolation(p : Double) -> Double { return p } // MARK: Quadratic easing; p^2 class func QuadraticEaseIn(p : Double) -> Double { return p * p } class func QuadraticEaseOut(p : Double) -> Double { return -(p * (p - 2)) } class func QuadraticEaseInOut(p : Double) -> Double { if (p < 0.5) { return 2 * p * p } else { return (-2 * p * p) + (4 * p) - 1 } } // MARK: Cubic easing; p^3 class func CubicEaseIn(p : Double) -> Double { return p * p * p } class func CubicEaseOut(p : Double) -> Double { let f : Double = (p - 1) return f * f * f + 1 } class func CubicEaseInOut(p : Double) -> Double { if (p < 0.5) { return 4 * p * p * p } else { let f : Double = ((2 * p) - 2) return 0.5 * f * f * f + 1 } } // MARK: Quartic easing; p^4 class func QuarticEaseIn(p : Double) -> Double { return p * p * p * p } class func QuarticEaseOut(p : Double) -> Double { let f : Double = (p - 1) return f * f * f * (1 - p) + 1 } class func QuarticEaseInOut(p : Double) -> Double { if(p < 0.5) { return 8 * p * p * p * p } else { let f : Double = (p - 1); return -8 * f * f * f * f + 1 } } // MARK: Quintic easing; p^5 class func QuinticEaseIn(p : Double) -> Double { return p * p * p * p * p } class func QuinticEaseOut(p : Double) -> Double { let f : Double = (p - 1) return f * f * f * f * f + 1 } class func QuinticEaseInOut(p : Double) -> Double { if (p < 0.5) { return 16 * p * p * p * p * p } else { let f : Double = ((2 * p) - 2) return 0.5 * f * f * f * f * f + 1 } } // MARK: Sine wave easing; sin(p * PI/2) class func SineEaseIn(p : Double) -> Double { return sin((p - 1) * M_PI_2) + 1 } class func SineEaseOut(p : Double) -> Double { return sin(p * M_PI_2) } class func SineEaseInOut(p : Double) -> Double { return 0.5 * (1 - cos(p * M_PI)) } // MARK: Circular easing; sqrt(1 - p^2) class func CircularEaseIn(p : Double) -> Double { return 1 - sqrt(1 - (p * p)) } class func CircularEaseOut(p : Double) -> Double { return sqrt((2 - p) * p) } class func CircularEaseInOut(p : Double) -> Double { 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) } } // MARK: Exponential easing, base 2 class func ExponentialEaseIn(p : Double) -> Double { return (p == 0.0) ? p : pow(2, 10 * (p - 1)) } class func ExponentialEaseOut(p : Double) -> Double { return (p == 1.0) ? p : 1 - pow(2, -10 * p) } class func ExponentialEaseInOut(p : Double) -> Double { 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 } } // MARK: Exponentially-damped sine wave easing class func ElasticEaseIn(p : Double) -> Double { return sin(13 * M_PI_2 * p) * pow(2, 10 * (p - 1)) } class func ElasticEaseOut(p : Double) -> Double { return sin(-13 * M_PI_2 * (p + 1)) * pow(2, -10 * p) + 1 } class func ElasticEaseInOut(p : Double) -> Double { 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) } } // MARK: Overshooting cubic easing class func BackEaseIn(p : Double) -> Double { return p * p * p - p * sin(p * M_PI) } class func BackEaseOut(p : Double) -> Double { let f : Double = (1 - p); return 1 - (f * f * f - f * sin(f * M_PI)) } class func BackEaseInOut(p : Double) -> Double { if (p < 0.5) { let f : Double = 2 * p return 0.5 * (f * f * f - f * sin(f * M_PI)) } else { let f : Double = (1 - (2*p - 1)) let tmp : Double = (f * f * f - f * sin(f * M_PI)) return 0.5 * (1 - tmp) + 0.5 } } // MARK: Exponentially-decaying bounce easing class func BounceEaseIn(p : Double) -> Double { return 1 - BounceEaseOut(1 - p) } class func BounceEaseOut(p : Double) -> Double { 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 } } class func BounceEaseInOut(p : Double) -> Double { if (p < 0.5) { return 0.5 * BounceEaseIn(p*2) } else { return 0.5 * BounceEaseOut(p * 2 - 1) + 0.5 } } }
// // EasingValue.swift // Swift-EasingAnimation // // Created by YouXianMing on 15/10/21. // // https://github.com/YouXianMing // http://home.cnblogs.com/u/YouXianMing/ // import UIKit class EasingValue: NSObject { // MARK: var /// 动画函数 var function : EasingFunction! /// 关键帧点数 var frameCount : size_t! // MARK: init override init() { super.init() function = EasingFunction.SineEaseIn frameCount = 60 } init(withFunction : EasingFunction, frameCount : size_t) { super.init() self.function = withFunction self.frameCount = frameCount } // MARK: func /** 计算关键帧 - parameter fromValue: 起始值 - parameter toValue: 结束值 - returns: 关键帧值数组 */ func frameValueWith(fromValue fromValue : Double, toValue : Double) -> [AnyObject] { let values = NSMutableArray(capacity: frameCount) var t : Double = 0.0 let dt : Double = 1.0 / (Double(frameCount) - 1) for var i = 0; i < frameCount; ++i, t += dt { let value = fromValue + (function.value())(t) * (toValue - fromValue) values.addObject(value) } return values as [AnyObject] } /** 计算关键帧点 - parameter fromPoint: 起始点 - parameter toPoint: 结束点 - returns: 关键帧点数组 */ func pointValueWith(fromPoint fromPoint : CGPoint, toPoint : CGPoint) -> [AnyObject] { let values = NSMutableArray(capacity: frameCount) var t : Double = 0.0 let dt : Double = 1.0 / (Double(frameCount) - 1) for var i = 0; i < frameCount; ++i, t += dt { let x : Double = Double(fromPoint.x) + (function.value())(t) * (Double(toPoint.x) - Double(fromPoint.x)) let y : Double = Double(fromPoint.y) + (function.value())(t) * (Double(toPoint.y) - Double(fromPoint.y)) let point : CGPoint = CGPoint(x : x, y : y) values.addObject(NSValue(CGPoint: point)) } return values as [AnyObject] } /** 计算关键帧尺寸 - parameter fromSize: 起始尺寸 - parameter toSize: 结束尺寸 - returns: 关键帧尺寸数组 */ func sizeValueWith(fromSize fromSize : CGSize, toSize : CGSize) -> [AnyObject] { let values = NSMutableArray(capacity: frameCount) var t : Double = 0.0 let dt : Double = 1.0 / (Double(frameCount) - 1) for var i = 0; i < frameCount; ++i, t += dt { let width : Double = Double(fromSize.width) + (function.value())(t) * (Double(toSize.width) - Double(fromSize.width)) let height : Double = Double(fromSize.height) + (function.value())(t) * (Double(toSize.height) - Double(fromSize.height)) let size : CGSize = CGSize( width, height: height) values.addObject(NSValue(CGSize : size)) } return values as [AnyObject] } }
// // ComplexEasingValue.swift // Swift-EasingAnimation // // Created by YouXianMing on 15/10/21. // // https://github.com/YouXianMing // http://home.cnblogs.com/u/YouXianMing/ // import UIKit class ComplexEasingValue: EasingValue { /// 点A的动画函数(如果是 size,则点 A 表示 width;如果是 point,则点 A 表示 x) var functionA : EasingFunction! /// 点B的动画函数(如果是 size,则点 B 表示 height;如果是 point,则点 B 表示 y) var functionB : EasingFunction! // MARK: init override init() { super.init() functionA = EasingFunction.SineEaseIn functionB = EasingFunction.SineEaseIn frameCount = 60 } init(withFunctionA : EasingFunction, FunctionB : EasingFunction, frameCount : size_t) { super.init() functionA = withFunctionA functionB = FunctionB self.frameCount = frameCount } /** 计算关键帧 - parameter fromValue: 起始值 - parameter toValue: 结束值 - returns: 关键帧值数组 */ override func pointValueWith(fromPoint fromPoint : CGPoint, toPoint : CGPoint) -> [AnyObject] { let values = NSMutableArray(capacity: frameCount) var t : Double = 0.0 let dt : Double = 1.0 / (Double(frameCount) - 1) for var i = 0; i < frameCount; ++i, t += dt { let x : Double = Double(fromPoint.x) + (functionA.value())(t) * (Double(toPoint.x) - Double(fromPoint.x)) let y : Double = Double(fromPoint.y) + (functionB.value())(t) * (Double(toPoint.y) - Double(fromPoint.y)) let point : CGPoint = CGPoint(x : x, y : y) values.addObject(NSValue(CGPoint: point)) } return values as [AnyObject] } /** 计算关键帧点 - parameter fromPoint: 起始点 - parameter toPoint: 结束点 - returns: 关键帧点数组 */ override func sizeValueWith(fromSize fromSize : CGSize, toSize : CGSize) -> [AnyObject] { let values = NSMutableArray(capacity: frameCount) var t : Double = 0.0 let dt : Double = 1.0 / (Double(frameCount) - 1) for var i = 0; i < frameCount; ++i, t += dt { let width : Double = Double(fromSize.width) + (functionA.value())(t) * (Double(toSize.width) - Double(fromSize.width)) let height : Double = Double(fromSize.height) + (functionB.value())(t) * (Double(toSize.height) - Double(fromSize.height)) let size : CGSize = CGSize( width, height: height) values.addObject(NSValue(CGSize : size)) } return values as [AnyObject] } }
细节