核心動畫的基礎接口以及爲擁有Layer的View作的動畫擴展接口,使得爲Layer製做複雜動畫變得簡單化。例如改變Layer的frame的size、改變Layer在屏幕上的position、應用旋轉transform、或者改變它的opacity。經過使用核心動畫,建立一個動畫效果將會變得簡單的就像修改屬性同樣,可是咱們也能顯式的建立和設置動畫參數。
關於建立更多高級動畫能夠參見Advanced Animation Tricks(後續會有譯文)。html
根據須要,咱們能夠選擇顯式或者隱式的執行簡單的動畫。隱式的動畫使用默認的速度調節和動畫屬性來執行動畫;相反,隱式動畫須要咱們使用核心動畫對象配置相應的屬性。所以當咱們想要使用少許代碼和默認定時速度作動畫過分改變的時候,隱式動畫是個不錯的選擇。ios
簡單的動畫意味着改變Layer的屬性,和讓核心動畫是這些改變隨着時間發生變化。Layers定義了許多可以影響可視化外觀的屬性,改變這些屬性之一就會引發相應的外觀動畫性的變化;例如,改變Layer的opacity由1.0到0.0將會引發Layer漸漸隱藏(淡出)並變透明。算法
重要提示:咱們有時能夠直接使用核心動畫的接口爲Layer-backed View(iOS 內的view均可稱爲此種view,前面章節有說明)作動畫,這麼作經常須要一些額外的步驟,更多關於如何使用與Layer-backed views結合的動畫能夠參見如何爲Layer-Backed View作動畫。數組
爲了觸發隱式動畫,咱們只須要去更新Layer對象的屬性。當更改圖層樹上的Layer對象的時候,Layer的屬性將會馬上變動爲咱們調整的值,然而Layer對象的外觀不會馬上改變爲咱們設置的值;相反,核心動畫使用咱們調整的值做爲觸發器來建立和規劃一個或多個隱式動畫,而後核心動畫並執行這些動畫。所以,像代碼3-1中調整屬性值將會引發核心動畫建立動畫對象,並規劃那個動畫到下個更新循環開始執行。app
Listing 3-1 Animating a change implicitlyide
theLayer.opacity = 0.0;
爲了製做和隱式動畫同樣的動畫,咱們也可經過顯示的使用動畫對象,建立一個CABasicAnimation 對象和使用那個對象配置動畫參數。在將動畫對象添加到Layer上以前,咱們能夠爲動畫對象設置開始和結束值、改變更畫週期,或者任何其餘的動畫參數。代碼3-2展現瞭如何經過動畫對象將Layer漸隱。當建立動畫對象後,咱們指定要作動畫的屬性的Key path,而後設置動畫參數。爲了執行動畫,咱們使用addAnimation:forKey:方法將動畫對象添加到Layer上。函數
Listing 3-2 Animating a change explicitlyoop
CABasicAnimation* fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"]; fadeAnim.fromValue = [NSNumber numberWithFloat:1.0]; fadeAnim.toValue = [NSNumber numberWithFloat:0.0]; fadeAnim.duration = 1.0; [theLayer addAnimation:fadeAnim forKey:@"opacity"]; // Change the actual data value in the layer to the final value. theLayer.opacity = 0.0;
提示:當建立顯示動畫的時候,建議爲動畫對象設置fromValue屬性值,若是咱們不指定這個值,核心動畫將會使用Layer的當前值做爲動畫的開始值,若是咱們將這個屬性值設定的和動畫的最終值一致,那麼將不會產生咱們想要的動畫效果。佈局
和隱式動畫不同的是,隱式動畫將會更改Layer對象的值,顯示動畫不會修改圖層樹上的數據。顯示動畫僅僅產生動畫效果。在動畫的結束後,核心動畫將會從Layer上移除動畫對象並使用Layer的當前值從新繪製。若是咱們想要顯示動畫的改變發生到Layer上,那麼咱們必須也更新Layer的屬性,就像3-2中指出的同樣。動畫
隱式和顯示動畫一般在當前runloop循環結束後就開始執行,爲了動畫對象的執行,當前線程必須有一個runloop。若是咱們改變多個屬性,若是爲Layer添加多個動畫對象,全部這些屬性將會同時發生動畫。例如咱們經過同時設置兩個動畫,就可使得隱藏一個Layer和將Layer移動到屏幕外面的同時發生。咱們一能夠設置動畫對象在某個特殊的時間點開始。關於更多的修改動畫的時間函數參見 Customizing the Timing of an Animation(後續會有譯文)。
屬性動畫經過改編屬性從開始值到結束值發生動畫, CAKeyframeAnimation 對象將會經過設定線性或者非線性目標值點集合的方式製做動畫。一個關鍵幀動畫由目標集合點,和與單個目標點對應的時間點的集合組成。最簡單的配置就是,咱們僅僅經過使用數組指定這兩種值。對於改變Layer的position來講,咱們也能夠指定它沿着path發生變化。動畫對象取咱們指定的關鍵幀並經過一個值到下一個值在給定的時間片刻上進行插值創建動畫。
圖3-1顯示了Layer的position屬性5s的動畫。Position是沿着一條path作的動畫,就是使用CGPathRef數據類型制定的path。對應的代碼見代碼3-3。
代碼3-3展現瞭如何實現圖3-1中動畫的代碼。在這個例子中,path對象是被用來定義每幀動畫中Layer的position。
Listing 3-3 Creating a bounce keyframe animation
// create a CGPath that implements two arcs (a bounce) CGMutablePathRef thePath = CGPathCreateMutable(); CGPathMoveToPoint(thePath,NULL,74.0,74.0); CGPathAddCurveToPoint(thePath,NULL,74.0,500.0, 320.0,500.0, 320.0,74.0); CGPathAddCurveToPoint(thePath,NULL,320.0,500.0, 566.0,500.0, 566.0,74.0); CAKeyframeAnimation * theAnimation; // Create the animation object, specifying the position property as the key path. theAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"]; theAnimation.path=thePath; theAnimation.duration=5.0; // Add the animation to the layer. [theLayer addAnimation:theAnimation forKey:@"position"];
關鍵幀的值是關鍵幀動畫最重要的一部分。關鍵幀的值明確了動畫執行的路線。主要指定關鍵幀值的方式是使用數組,可是對於當數組中包含CGPoint數據類型的時候(例如Layer的anchorPoint和position屬性),咱們也能夠指定CGPathRef數據類型代替。
當指定數組值的時候,數組中應該放的數據類型取決於要作動畫的屬性。咱們能夠將某些對象直接添加到數組中;可是有些類型必須先轉換到id對象類型在添加以前,全部的標量類型和結構體必須先包裝成對象,例如:
對於對應CGPoint數據類型的屬性,咱們能夠建立point的數組(先包裝成NSValue對象)或者使用CGPathRef對象指定動畫的路線。當咱們指定point的數組的時候,關鍵幀動畫對象建立的動畫將會走直線在相鄰的點。當咱們指定CGPathRef對象,動畫從路徑的起點開始,並沿着他的輪廓走,若是是曲線,它也可以沿着曲線的路徑走。咱們也可使用非閉合或者閉合的路徑。
關鍵幀的時間函數和空間位置是比基本動畫(basic animations)更復雜的,這裏有幾個供控制它們的屬性:
若是咱們想要本身控制時間函數,須要採用 kCAAnimationLinear或kCAAnimationCubic 模式和keyTimes以及timingFunctions屬性。keytimes屬性指定應用於對應幀值的時間點。timeingFunctions用於控制全部時間的插值,它將容許在每一個片斷咱們應用緩入或者緩出。若是咱們不指定timingFunctions時間函數將會是線性的。
正常狀況下動畫會運行到動畫完成,可是若是有須要,咱們可以經過如下方式提早移除它們:
注意:咱們不能從Layer直接移除隱式動畫。
當咱們從Layer上面移除動畫的時候,核心動畫將會響應——使用Layer當前的值重繪Layer。由於一般是動畫的最終值(end values),這可能引發Layer的樣貌發生跳躍性的變化。若是咱們想要Layer的樣貌保持在動畫的最後一幀,咱們可使用呈現樹上的Layer對象獲取最終值(若是是移除操做也能夠稱爲,動畫當前值)並設置他們這些值到圖層樹。
更多關於臨時暫停動畫可參見代碼5-4(後續會有譯文)。
若是咱們想要將多個動畫同時應用到Layer對象,咱們能夠將他們綁定在一塊兒經過使用CAAnimationGroup對象,group對象能夠以簡單的配置簡化多個動畫對象的管理。設置到group對象的時間函數和duration值將會覆蓋單個動畫對象對應的值。
代碼3-4展現瞭如何使用一個group對象以相同的時間函數和相同時間週期的實現兩個邊框相關的動畫。
Listing 3-4 Animating two animations together
// Animation 1 CAKeyframeAnimation* widthAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderWidth"]; NSArray* widthValues = [NSArray arrayWithObjects:@1.0, @10.0, @5.0, @30.0, @0.5, @15.0, @2.0, @50.0, @0.0, nil]; widthAnim.values = widthValues; widthAnim.calculationMode = kCAAnimationPaced; // Animation 2 CAKeyframeAnimation* colorAnim = [CAKeyframeAnimation animationWithKeyPath:@"borderColor"]; NSArray* colorValues = [NSArray arrayWithObjects:(id)[UIColor greenColor].CGColor, (id)[UIColor redColor].CGColor, (id)[UIColor blueColor].CGColor, nil]; colorAnim.values = colorValues; colorAnim.calculationMode = kCAAnimationPaced; // Animation group CAAnimationGroup* group = [CAAnimationGroup animation]; group.animations = [NSArray arrayWithObjects:colorAnim, widthAnim, nil]; group.duration = 5.0; [myLayer addAnimation:group forKey:@"BorderChanges"];
Transaction對象可以提供將動畫組合在一塊兒的更高級方式。Transcation經過容許咱們建立嵌套的動畫集和爲每一個動畫關聯不一樣動畫參數,也所以Transcation更靈活,更多關於如何使用Transaction對象,可參見 Explicit Transactions Let You Change Animation Parameters(後續會有譯文)。
核心動畫提供獲取動畫開始和結束事件的支持。這些通知對於動畫輔助任務來講是很好的時間點。例如咱們能夠藉助獲取到開始通知時去設置一些相關聯的狀態信息並使用對應的結束通知撤銷這些狀態。
有一下兩種不一樣的獲取方式:
若是咱們想要去將兩個動畫銜接在一塊兒,實現當一個結束另一個就開啓,不要使用動畫通知,相反的應該使用動畫對象的beginTime屬性去開啓每個動畫在指望的時間點。爲了將兩個動畫先後銜接在一塊兒,設置第二個動畫的start爲第一個動畫的end時間。更多關於動畫和時間值的信息參見Customizing the Timing of an Animation(後續會有譯文)。
若是Layer屬於Layer-backed view,動畫建立的推薦方式是使用經過UIKit或AppKit提供的基於View的動畫接口。經過使用核心動畫接口,有許多方式能夠爲Layer作動畫,可是如何建立這些動畫取決於所在的目標平臺(iOS 、OSX)。
由於iOS中的view一直都有一個內在的Layer,UiView類直接從layer對象直接獲取許多數據,這就致使咱們爲Layer作的調整也會在View對象上自動提現出來,這就意味着咱們可使用核心動畫或者UIView的接口來實現這些調整。
基於Layer-backed View,若是咱們想要使用核心動畫建立動畫,咱們必須在基於view的動畫block內部發起全部的核心動畫的調用。UIView類默認禁用了Layer動畫,可是在動畫bolcks中能夠激活,所以任何在bolcks外的Layer調整將不會發生動畫。代碼3-5展現了基於Layer-backed View內如何爲Layer製做opacity隱式動畫,和position顯示動畫。在這個例子中,myNewPosition變量是被提早計算並被block捕獲到的。兩個動畫在同一時間開始,可是opacity動畫一默認的時間函數運行,position動畫以他動畫對象所指定的時間函數運行。
Listing 3-5 Animating a layer attached to an iOS view
[UIView animateWithDuration:1.0 animations:^{ // Change the opacity implicitly. myView.layer.opacity = 0.0; // Change the position explicitly. CABasicAnimation* theAnim = [CABasicAnimation animationWithKeyPath:@"position"]; theAnim.fromValue = [NSValue valueWithCGPoint:myView.layer.position]; theAnim.toValue = [NSValue valueWithCGPoint:myNewPosition]; theAnim.duration = 3.0; [myView.layer addAnimation:theAnim forKey:@"AnimateFrame"]; }];
若是使用基於約束的佈局規則管理views的position,那麼做爲配置動畫的一部分,咱們必須移除任何影響動畫的約束。約束影響任何咱們爲view的position或size作的調整,他們經常影響view之間以及view和他們子view的關係;若是咱們爲這些帶有約束的view作動畫,咱們須要移除這些約束,並應用咱們須要的新的約束。
更多關於約束和如何使用他們管理views的layout的信息參見Auto Layout Guide。