有些時候你們可能會遇到製做複雜、具備連貫性UIView動畫的需求,這時你們可能會使用在completion
閉包中銜接一段一段的動畫,使之成爲一段連續的動畫。閉包
若是咱們只是鏈接2個,或者3個動畫,這種方式或許還行得通,但若是有更多的動畫片斷須要鏈接的時候,這種方式會帶來災難性的問題,你的代碼會很是的冗餘,不斷的在completion
閉包中嵌套代碼,使代碼維護起來至關的困難。因此今天向你們介紹能更好地實現這個需求的方法,Keyframe動畫。app
Keyframe動畫可讓咱們有效的拆分由若干段動畫鏈接而成的複雜動畫,能夠較爲精準的定義每段動畫的起始點及持續時間,而且在代碼組織方面也很是清晰。先看看今天要帶你們實現的動畫Demo:動畫
咱們先來認識一下,在什麼樣的場景下須要使用Keyframe動畫。如圖下所示,這是一個由四段動畫組成的一個複雜動畫,讓UIView沿着長方形的軌跡運動:spa
咱們來看看用代碼如何實現:.net
[cpp] view plaincopyrest
UIView.animateWithDuration(1, animations: { code
view.center.x += 200.0 orm
}, completion: { _ in ip
UIView.animateWithDuration(1, animations: { 文檔
view.center.y += 100.0
}, completion: { _ in
UIView.animateWithDuration(1, animations: {
view.center.x -= 200.0
}, completion: { _ in
UIView.animateWithDuration(1, animations: {
view.center.y -= 100.0
}, completion: nil)
})
})
})
經過上面的僞代碼能夠看到,咱們使用了completion
閉包的方式鏈接每一段的動畫,代碼看起來尚且算清晰,可讀性也馬馬虎虎。可是你們想象一下,若是咱們使UIView按照一個複雜的路線運行,這一段動畫可能有十幾、幾十段動畫組成的,那麼若是再使用completion
閉包這種方式鏈接,那代碼是多麼的慘不忍睹。幸虧咱們有Keyframe動畫,下面就讓咱們來看看如何使用Keyframe動畫。
首先咱們會使用到UIView的另外一個動畫方法animateKeyframesWithDuration(_: delay: options: animations: completion: )
:
[cpp] view plaincopy
UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {
// add keyframes
}, completion: nil)
這個方法的幾個參數與前幾個使用過的動畫方法參數同樣。上面代碼片斷的意思是整個關鍵幀動畫的持續時間爲2秒、無延遲、無動畫選項、執行完畢後無後續執行的代碼。
注:該方法的動畫選項再也不是
UIViewAnimationOptions
,而是UIViewKeyframeAnimationOptions
。具體的內容你們能夠去查閱Apple的文檔。
接下來咱們要在animations
閉包中添加關鍵幀了:
[cpp] view plaincopy
UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {
view.center.x += 200.0
})
}, completion: nil)
addKeyframeWithRelativeStartTime(_: relativeDuration: animations: )
是UIView添加關鍵幀的方法,該方法有三個參數:
startTime:關鍵幀開始時間,該時間是相對整個關鍵幀動畫持續時間的相對時間,通常值在0到1之間。若是爲0,則代表這一關鍵幀從整個動畫的第0秒開始執行,若是設爲0.5,則代表從整個動畫的中間開始執行。
relativeDuration:關鍵幀持續時間,該時間一樣是相對整個關鍵幀動畫持續時間的相對時間,通常值也在0到1之間。若是設爲0.25,則代表這一關鍵幀的持續時間爲整個動畫持續時間的四分之一。
animations:設置視圖動畫屬性的動畫閉包。
咱們解釋一下上面這段代碼。整個關鍵幀動畫的持續時間爲2秒,第一個關鍵幀從第0秒開始,運行0.5秒結束。下面咱們完成其餘三個關鍵幀:
[cpp] view plaincopy
UIView.animateKeyframesWithDuration(2, delay: 0, options: [], animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.25, animations: {
view.center.x += 200.0
})
UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25, animations: {
view.center.y += 100.0
})
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.25, animations: {
view.center.x -= 200.0
})
UIView.addKeyframeWithRelativeStartTime(0.75, relativeDuration: 0.25, animations: {
view.center.y -= 100.0
})
}, completion: nil)
第二個關鍵幀的開始時間爲0.25,也就是從整個動畫時間的第0.5時開始執行,一樣持續0.5秒。後兩個關鍵幀的參數就不難理解了。
如今整個代碼看起來很是整潔,條理清晰,可讀性很是好,並且能夠有更精確的控制。即便再多幾個關鍵幀也一樣能夠從容應對。
關鍵幀動畫不只僅用於同一個視圖的分段動畫,也可以使使用於不一樣視圖的組合動畫,因爲咱們還沒講到圖層動畫,因此,開篇的示例動畫中就使用了關鍵幀動畫實現了多個視圖的組合動畫。
在這個示例中雖然看起來是一個紙飛機視圖的連續動畫,但實際上是由三個紙飛機視圖組合而成的:
從圖中能夠看到實際上是有三個紙飛機視圖,只不過在界面加載以前2號和3號紙飛機視圖的透明度都是爲零。
整個動畫是由這三個紙飛機視圖經過關鍵幀動畫組合而成:
圖中標示出了三個飛機視圖的運行軌跡、視圖大小、視圖透明度的狀態,咱們來看看代碼如何實現:
[cpp] view plaincopy
let zoomInScaleTransform = CGAffineTransformMakeScale(0.2, 0.2)
UIView.animateKeyframesWithDuration(3, delay: 0, options: [], animations: {
UIView.addKeyframeWithRelativeStartTime(0, relativeDuration: 0.2, animations: {
self.customHeaderView.paperAirplane.center.x += self.view.frame.width
self.customHeaderView.paperAirplane.center.y += -180
self.customHeaderView.paperAirplane.transform = zoomInScaleTransform
})
UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.01, animations: {
self.customHeaderView.paperAirplaneOpposite.alpha = 1
self.customHeaderView.paperAirplaneOpposite.transform = zoomInScaleTransform
})
UIView.addKeyframeWithRelativeStartTime(0.3, relativeDuration: 0.5, animations: {
self.customHeaderView.paperAirplaneOpposite.transform = CGAffineTransformIdentity
self.customHeaderView.paperAirplaneOpposite.center.x -= self.view.frame.width
self.customHeaderView.paperAirplaneOpposite.center.y += 90
})
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.01, animations: {
self.customHeaderView.paperAirplaneComeBack.alpha = 1
})
UIView.addKeyframeWithRelativeStartTime(0.9, relativeDuration: 0.2, animations: {
self.customHeaderView.paperAirplaneComeBack.center.x += 33
})
}, completion: { _ in
self.restorePaperAirplaneStatus()
})
你們看到這你們可能會有疑問了,三段動畫怎麼會有五個關鍵幀呢,咱們來刨析一下:
第一個關鍵幀:完成1號紙飛機視圖運動到右上角並移出屏幕,視圖逐漸變小的動畫。該關鍵幀從整個動畫的第0秒開始執行,持續時間爲0.6秒。
第二個關鍵幀:因爲2號紙飛機視圖的初始透明度爲零,因此在第二個關鍵幀將透明度設爲1,而且縮小視圖。注意這兩個動做須要在瞬間完成,因此relativeDuration
設爲0.01,一個極短的時間。開始時間爲整個動畫的第0.9秒開始,較第一個關鍵幀延遲0.3秒。
第三個關鍵幀:與第二個關鍵幀同時開始執行,完成2號紙飛機視圖從小變大、而且往左下角運動,一直移出屏幕。持續時間爲1.5秒。
第四個關鍵幀:與第二個關鍵幀做用類似,改變3號紙飛機視圖的透明度,一樣是在瞬間完成。
第五個關鍵幀:與第四個關鍵幀同時執行, 完成向右移動的動畫,持續0.6秒。
關鍵幀完成以後,在completion
閉包中調用restorePaperAirplaneStatus()
方法,恢復3個紙飛機視圖的狀態及位置,以便再次執行動畫。
你們在使用關鍵幀動畫時,對於關鍵幀的開始時間和持續時間須要仔細設置,保證每一個關鍵幀在合適的時間開始,執行恰當的持續時間。在必要時候也須要在關鍵幀裏修改視圖的一些狀態,但要設置極短的持續時間,表示瞬間完成。
下一篇會向你們介紹在使用Auto Layout的狀況下,如何經過約束實現動畫,好了今天就先到這裏吧。