Layer 上的 Keyframe 動(dòng)畫與 UIView 上的關(guān)鍵幀動(dòng)畫有些不同洋腮。UIView 關(guān)鍵幀動(dòng)畫是將獨(dú)立的簡(jiǎn)單動(dòng)畫組合在一起的一種簡(jiǎn)單方法夏哭。它們可以使不同的視圖和屬性產(chǎn)生動(dòng)畫效果,動(dòng)畫可以重疊珠十,或者中間有空隙。
相反,CAKeyframeAnimation 允許我們對(duì)給定 Layer 上的單個(gè)屬性進(jìn)行動(dòng)畫處理谜洽。我們可以定義動(dòng)畫的不同關(guān)鍵點(diǎn),但是動(dòng)畫不能有任何間隙或重疊吴叶。
keyframe animations
通過(guò)使用 fromValue 和 toValue阐虚,Core Animation 在指定的持續(xù)時(shí)間內(nèi)逐步修改這些值之間的特定層屬性。
比如蚌卤,當(dāng)旋轉(zhuǎn)一個(gè) layer 45°实束、-45°(或π/ 4和-π/ 4),我們只需要指定這兩個(gè)值逊彭,層會(huì)渲染 π/ 4 和 -π/ 4 之間的所有中間值來(lái)完成動(dòng)畫咸灿。
CAKeyframeAnimation 使用 array of values 來(lái)動(dòng)畫,而不是由 fromValue 到 toValue 那樣動(dòng)畫侮叮。array 中的值的是動(dòng)畫的關(guān)鍵值避矢。除此,我們還需要提供動(dòng)畫應(yīng)該到達(dá)每個(gè)值的關(guān)鍵點(diǎn)的時(shí)間囊榜。
上面的動(dòng)畫审胸,layer 從 45° 旋轉(zhuǎn)到 -45° ,但這次有兩個(gè)不同的階段:首先,前三分之二時(shí)間里它從 45° 旋轉(zhuǎn)到 22°卸勺,剩下的時(shí)間里砂沛,它從 22° 旋轉(zhuǎn)到 -45°。
Animating struct values
Struct instances 是 Swift 中的一等公民曙求,在語(yǔ)法上碍庵,處理類和結(jié)構(gòu)體之間沒有什么區(qū)別。
然而悟狱,Core Animation 是構(gòu)建在 C 上的 Objective-C 框架静浴,這意味著結(jié)構(gòu)體的處理方式非常不同。Objective-C api 喜歡處理對(duì)象挤渐,所以結(jié)構(gòu)體需要一些特殊的處理苹享。
這就是為什么將諸如 color 或 number 的 layer 屬性進(jìn)行動(dòng)畫是相對(duì)容易的,但是對(duì)諸如 CGPoint 這樣的結(jié)構(gòu)體屬性進(jìn)行動(dòng)畫并不那么容易的原因挣菲。
CALayer 的許多可動(dòng)畫屬性都具有 struct 值富稻,包括 CGPoint 類型的 position掷邦、CATransform3D 類型的 transform 以及 CGRect 類型的 bounds 。為了幫助管理椭赋,Cocoa 包含 NSValue 類抚岗,它可以將一個(gè) struct 值 “裝箱” 或 “包裝” 成為對(duì)象。
NSValue 附帶了許多方便的初始化方法哪怔,我們可以將它們用于需要裝箱的每個(gè)結(jié)構(gòu)體宣蔚,例如如下初始化方法:
init(cgPoint: CGPoint)
init(cgSize: CGSize)
init(cgRect rect: CGRect)
init(caTransform3D: CATransform3D)
“boxes in” or “wraps” “裝箱” 或 “包裝”使用示例:
let move = CABasicAnimation(keyPath: "position")
move.duration = 1.0
move.fromValue = NSValue(cgPoint: CGPoint(x: 100.0, y: 100.0))
move.toValue = NSValue(cgPoint: CGPoint(x: 200.0, y: 200.0))
Intermediate keyframe animations
let balloon = CALayer()
balloon.contents = UIImage(named: "balloon")!.cgImage
balloon.frame = CGRect(x: -50.0, y: 0.0, width:50.0, height: 65.0) view.layer.insertSublayer(balloon, below: username.layer)
如果我們想要在屏幕上顯示一個(gè)圖像,但不需要使用 UIView 的一些特性(比如自動(dòng)布局約束认境、附加手勢(shì)識(shí)別器等等)胚委,那么我們可以使用一個(gè) CALayer 添加圖像,如上面的代碼示例叉信。
flight.values = [
CGPoint(x: -50.0, y: 0.0),
CGPoint(x: view.frame.width + 50.0, y: 160.0),
CGPoint(x: -50.0, y: loginButton.center.y)
].map { NSValue(cgPoint: $0) } // 使用map將一個(gè)點(diǎn)數(shù)組巧妙地轉(zhuǎn)換成一個(gè)以nsvalue形式框起來(lái)的點(diǎn)數(shù)組
flight.keyTimes = [0.0, 0.5, 1.0]
使用 map 將一個(gè) CGPoint 數(shù)組巧妙地轉(zhuǎn)換成一個(gè)以 NSValue 形式框起來(lái)的點(diǎn)數(shù)組亩冬。
動(dòng)畫最后效果: