彈性動畫一直以來都深深地吸引我,隨著知識儲備增多拂封,漸漸探索出一套彈性動畫的實現(xiàn)原理茬射。
簡介
本文將從零開始,一步步解析彈性動畫原理冒签,包教包會在抛。本文Demo簡單地封裝了一個動畫庫來測試,支持UIView
的三種動畫類型:Size
萧恕、Position
刚梭、Scale
,動畫運動曲線有:bounce
票唆、easeInOut
朴读。CALayer
動畫暫不支持。
運動曲線
從初中開始走趋,我們就開始接觸正弦曲線衅金、余弦曲線,現(xiàn)在真的排上用場了(后悔當初數(shù)學沒學好)吆视。我們可以通過對正弦余弦做一些處理典挑,來得到動畫的運動曲線。彈性動畫稍微復雜一些啦吧,主要分為兩部分,一是 波動(波形) 拙寡、二是 衰減 授滓,將二者結合就能得到我們想要的動畫運動曲線。
1. 淡入淡出運動曲線
** 正弦曲線 **,Y
坐標隨著X
坐標的變化而變化般堆,新手乍一看在孝,這跟動畫根本沒有半毛錢關系,我們還需要進行精加工處理淮摔,才能使用私沮。
不管是彈性動畫還是線性動畫,我們都有一個起點和終點和橙,彈性動畫不同的是它的值在某些時候會超越最終值仔燕,然后又回到最終值∧д校總之晰搀,我們需要一個絕對起點值為0,絕對終點值為1办斑,progress
值范圍在01外恕。舉個栗子,我們要從``(100,100)``移動到``(200乡翅,200)``鳞疲,x和y初始值和最終值相差100,減去初始值蠕蚜,這0100就是progress
的從0~1的過程尚洽。
不管是正弦還是余弦,經(jīng)過我們的翻轉(zhuǎn)位移之后都能得到一個從0到1的曲線:
這就是easeInOut
動畫的運動曲線圖波势,在開始和結尾比較平緩翎朱,而中間波動較大,即淡入淡出的效果尺铣。
2. 彈性運動曲線
**a. 衰減曲線 **彈性動畫中從0~1的過程主要由指數(shù)衰減函數(shù)來控制拴曲,指數(shù)倍數(shù)越小,衰減速度越快凛忿,在動畫參數(shù)中相當于 彈性阻尼澈灼。
b. 余弦曲線 在這里的我們使用余弦來作為彈性動畫波動曲線,x
倍數(shù)值越大店溢,振動頻率 越快叁熔。
**c. 衰減的余弦曲線 **衰減函數(shù)和余弦函數(shù)相乘,得到初步的彈性運動曲線床牧。
**d. 0~1的衰減的余弦曲線 荣回,將曲線函數(shù)翻轉(zhuǎn)(加負號)后上移1(+1)即可得到最終彈性曲線,曲線從0開始戈咳,y
值隨著x
值變化波動后漸漸平穩(wěn)歸于1心软。x
值遞增越快壕吹, 動畫速度 **越快,整個動畫所需時間越短删铃。
通過運動曲線生成動畫
1. CADisplayLink
CADisplayLink
是一個能讓我們以和屏幕刷新率相同的頻率將動畫顯示到屏幕上的定時器耳贬。通過定時器我們利用當前動畫progress
得出運動曲線當前Y
的值,即代碼中的timeLineY
猎唁。
舉個例子咒劲,移動position
的動畫,是用動畫的startPoint+(endPoint-startPoint)*timeLineY
=動畫當前progress
的的position
诫隅,當按順序?qū)⑦@些position
顯示出來就形成了我們需要的動畫腐魂。
// 新建一個displayLink
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisplayLink)];
- (void)updateDisplayLink {
// 獲取彈性動畫曲線當前進度的曲線的Y坐標
float timeLineY = [self getSpringAnimation:animation springOffset:animation.progress];
// +進度
animation.progress+=animation.speed;
// 使用Y坐標值 算出View當前位置
CGRect tempFrame = animationView.frame;
NSValue *fromValue = animation.fromValue;
CGPoint startPoint = fromValue.CGPointValue;
NSValue *toValue = animation.toValue;
CGPoint endPoint = toValue.CGPointValue;
tempFrame.origin.x = startPoint.x+(endPoint.x - startPoint.x)*timeLineY;
tempFrame.origin.y = startPoint.y+(endPoint.y - startPoint.y)*timeLineY;
animationView.frame = tempFrame;
}
下面將會提到各種動畫是如何獲取當前timeLineY
,提供了相應的曲線函數(shù)阎肝、代碼和動畫效果圖挤渔。
2. 非曲線動畫
非曲線意思就是0~1運動軌跡是直線遞增,整個動畫會顯得比較生硬风题。
函數(shù):y=x
動畫效果:
3. 淡入淡出動畫
EaseInOut曲線在動畫在起點和終點的位置遞增比較慢判导,動畫開啟和結束的地方比較平滑。
曲線函數(shù):
轉(zhuǎn)換成OC代碼:
- (CGFloat)getEaseInOutAnimation:(FDSpringAnimation *)animation springOffset:(CGFloat)x {
result = MIN(-cos(M_PI*animation.progress)/2.0+0.5, 1.000);
return result;
}
動畫效果:
4. 彈性動畫
彈性動畫增加了2個參數(shù)沛硅,分別是阻尼:damping
和波動頻率:frequency
眼刃。
曲線函數(shù):
轉(zhuǎn)換成OC代碼:
- (CGFloat)getSpringAnimation:(FDSpringAnimation *)animation springOffset:(CGFloat)x {
result = -pow(2, -animation.damping * x) * cos(animation.frequency*x)+1;
}
動畫效果:
拓展
上面的內(nèi)容基本可以實現(xiàn)一個簡單的彈性動畫,本文Demo在此基礎上增加了同時多個動畫運行
摇肌、completionBlock
等功能擂红,正在運行的動畫暫停
,移除正在運行的動畫
围小、替換正在運行的動畫
等功能待加入昵骤。
本文所有曲線通過Grapher
繪畫。
總結
以前一直都是直接用POP
或者UIView
動畫實現(xiàn)彈性動畫的效果肯适,對于原理實現(xiàn)不甚了解变秦,但是一直保持著好奇心,終于是自己實現(xiàn)了一套方案(路子比較野)框舔。
個人水平有限蹦玫,歡迎提出建議。