動(dòng)畫(huà)基礎(chǔ)
動(dòng)畫(huà)在UI交互中是一種增強(qiáng)用戶體驗(yàn)的利器彭沼,現(xiàn)在幾乎每一個(gè)移動(dòng)App都會(huì)使用到各種動(dòng)畫(huà)效果梭灿。蘋(píng)果Cocoa框架對(duì)動(dòng)畫(huà)效果的支持非常強(qiáng)大画侣,為開(kāi)發(fā)者提供了豐富的Api實(shí)現(xiàn)各類(lèi)動(dòng)畫(huà)效果。
iOS開(kāi)發(fā)中實(shí)現(xiàn)動(dòng)畫(huà)效果通常有三種方式堡妒。
- 基于
CALayer
的Core Animation
框架棉钧,這是動(dòng)畫(huà)的基礎(chǔ)框架。 - 基于
UIView
涕蚤,為了方便實(shí)現(xiàn)簡(jiǎn)單的動(dòng)畫(huà)封裝的UIView Animation
宪卿。 - 在游戲開(kāi)發(fā)中經(jīng)常用到的基于物理模擬的動(dòng)畫(huà)框架
UIKit Dynamics
。
核心動(dòng)畫(huà)
Core Animation
正如其名万栅,是所有動(dòng)畫(huà)的核心實(shí)現(xiàn)佑钾。它可以滿足我們對(duì)動(dòng)畫(huà)的所有要求。
可能最常見(jiàn)的情況是將一個(gè) view 的屬性從一個(gè)值改變?yōu)榱硪粋€(gè)值烦粒,比如
let animationX = CABasicAnimation()
animationY.keyPath = "position.x"
animationY.fromValue = 0
animationY.byValue = 300
animationY.duration = 2.0
animationX.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear)
這段代碼表示一個(gè)在x方向上從0線型移動(dòng)到300休溶,耗時(shí)2秒的動(dòng)畫(huà)代赁。可以看到
Core Animation
提供的API非常簡(jiǎn)潔兽掰,很容易理解芭碍。
時(shí)間函數(shù)
可以看到,上面的方塊是線型移動(dòng)的孽尽,這是因?yàn)槲覀冊(cè)O(shè)置了其動(dòng)畫(huà)的時(shí)間函數(shù)為CAMediaTimingFunction(name:kCAMediaTimingFunctionLinear)
窖壕。時(shí)間函數(shù)通過(guò)修改持續(xù)時(shí)間的分?jǐn)?shù)來(lái)控制動(dòng)畫(huà)的速度。
Core Animation
提供兩種方式創(chuàng)建時(shí)間函數(shù)杉女,一種是預(yù)定義的命名時(shí)間函數(shù):CAMediaTimingFunction(name:String)
-
淡入 (kCAMediaTimingFunctionEaseIn):
-
淡出 (kCAMediaTimingFunctionEaseOut):
-
淡入淡出 (kCAMediaTimingFunctionEaseInEaseOut):
- 默認(rèn) (kCAMediaTimingFunctionDefault):
另一種是通過(guò)傳入兩個(gè)控制點(diǎn)創(chuàng)建貝塞爾曲線(cubic Bézier)函數(shù):
CAMediaTimingFunction(c1x:Float,c1y:Float,c2x:Float,c2y:Float)
關(guān)于貝塞爾曲線的細(xì)節(jié)這里不展開(kāi)討論瞻讽,有興趣的看官們可以移步cubic-bezier.com,這個(gè)網(wǎng)站可以直接看到通過(guò)控制點(diǎn)創(chuàng)建的貝塞爾曲線的函數(shù)圖像熏挎,awesome速勇!
自定義時(shí)間函數(shù)
Core Animation
只提供了有限的時(shí)間函數(shù),能滿足我們大部分的需求坎拐。但是如果我們要實(shí)現(xiàn)類(lèi)似下圖的效果烦磁,方塊按照Sin正弦函數(shù)的方式進(jìn)行動(dòng)畫(huà),應(yīng)該怎么做呢哼勇?
為此我寫(xiě)了一個(gè)微型的庫(kù)——
TFAnimation
都伪,接收一個(gè)自定義的時(shí)間函數(shù),是一個(gè)(CGFloat) -> CGFloat
類(lèi)型的閉包猴蹂,其定義域?yàn)閇0,1]院溺。比如楣嘁,線型時(shí)間函數(shù)可以定義如下磅轻。
let animationY = TFBasicAnimation()
//指定其他的屬性,就像CABasicAnimation
animationY.keyPath = "position.y"
animationY.fromValue = 0
animationY.byValue = height / 4
animationY.duration = 5.0
animationY.additive = true
animationY.timeFunction = { $0 }
所以逐虚,實(shí)現(xiàn)上圖的效果聋溜,其實(shí)就是在x方向上時(shí)間函數(shù)是平移,在y方向上叭爱,時(shí)間函數(shù)是正弦函數(shù)
animationY.timeFunction = { -CGFloat(sin(4.0 * M_PI * Double($0)) }
其實(shí)實(shí)現(xiàn)的原理也很簡(jiǎn)單撮躁,代碼量也不多,核心思想是繼承CAKeyframeAnimation
买雾,把通過(guò)時(shí)間函數(shù)計(jì)算出相應(yīng)的幀位置把曼,填充到CAKeyframeAnimation.values
中。具體的實(shí)現(xiàn)我放在了github上漓穿,TFAnimation嗤军,直接運(yùn)行就是上圖的正弦動(dòng)畫(huà),走過(guò)路過(guò)的小伙伴隨手點(diǎn)個(gè)Star唄晃危!有任何意見(jiàn)建議的小伙伴歡迎評(píng)論留言~