本文首發地址html
翻譯說明
transaction - 事務
複製代碼
經過 Core Animation 提供的基礎,咱們能夠輕鬆的爲 app 的圖層建立複雜的動畫,並把動畫擴展到擁有圖層的視圖上。可動畫的例子包含:改變圖層的尺寸、改變圖層在屏幕上的位置、應用旋轉形變或者改變它的透明度。經過 Core Animation,初始化一個動畫一般和改變屬性的值同樣簡單,可是你也能夠建立一個動畫,而後顯式的設置動畫參數。git
關於建立高級動畫的更多信息,能夠參見高級動畫技巧。github
你能夠根據你的需求執行簡單的隱式動畫或者顯式動畫。隱式動畫使用默認時間和動畫屬性去執行動畫,而顯式動畫須要你去配置你使用的動畫對象的參數。因此隱式動畫更適用於你想執行一個沒有大量代碼的動畫改變,並且默認的時間對你是適用的。算法
簡單動畫包含改變圖層的屬性以及讓 Core Animation 隨着時間使這些改變更畫執行。圖層定義了不少影響視覺外觀的屬性。改變這些屬性是一種動畫改變圖層外觀的方式。例如,將圖層的透明度從 1.0 改成 0.0 會形成圖層淡出透明。數組
重要:雖然有時你能夠直接使用 Core Animation 的接口去執行圖層支持視圖的動畫,但這一般須要額外的步驟。關於如何共同使用 Core Animation 和圖層支持視圖的更多信息,請參見如何動畫圖層支持視圖。bash
你只須要更新圖層對象的屬性便可觸發隱式動畫。當在圖層樹上修改圖層對象時,這些對象會當即反應你的改變。然而,圖層對象的視覺外觀不會當即改變。Core Animation 會將你的修改當作一個觸發器,去建立和安排一個或者多個隱式動畫以供執行。所以,像 例3-1 的改變會形成 Core Animation 爲你建立一個動畫對象,而後在下次更新循環中開始運行這個動畫。app
例 3-1 隱式改變更畫ide
theLayer.opacity = 0.0;
複製代碼
使用一個動畫對象來製做顯式改變,建立一個 CABasicAnimation 對象,用該對象配置動畫參數。在將動畫添加到圖層以前,你能夠設置動畫的起止值,改變持續時間,或者改變更畫的其餘參數。例3-2 展現瞭如何經過使用動畫對象淡出圖層。當建立對象時,你指定你想動畫的屬性的關鍵路徑,而後設置動畫參數。爲了執行該動畫,你可使用 addAnimation:forKey:
方法將它添加到你想執行動畫的圖層上。oop
例 3-2 顯式改變更畫佈局
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"];
// 將圖層的實際數據改成結束值
theLayer.opacity = 0.0;
複製代碼
提示:當建立顯式動畫時,推薦你給動畫對象的 fromValue
屬性賦值。若是你沒給該屬性賦值,Core Animation 會使用圖層的當前值做爲起始值。若是你已經更新了該屬性的結束值,可能不會出現你想要的結果。
不像隱式動畫,它會更新圖層對象的數據值,顯式動畫不會修改圖層樹的數據。顯式動畫僅執行動畫。在動畫結束時,Core Animation 會從圖層移除動畫對象,而後使用圖層的當前數據值重繪圖層。若是你想顯式動畫的改變是永久的,你必須像前面的例子同樣更新圖層屬性。
隱式動畫和顯式動畫一般在當前 run loop 循環結束後開始執行,而且當前線程必須有 run loop 才能執行動畫。若是修改多個屬性,或者你對圖層添加多個動畫對象,全部的屬性改變更畫會同時執行。例如,你能夠在同一時間配置兩個動畫來實現淡出圖層的同時將它移動到屏幕外。然而,你也能夠配置動畫對象在特定的時間開始。關於修改動畫時間的更多信息,可參見自定義動畫時間。
基於屬性的動畫將屬性從起始值改變爲終止值,CAKeyframeAnimation 對象容許你經過一組目標值來實現動畫,它能夠是線性的,也能夠不是。一個關鍵幀是由一組目標值和目標值什麼時候執行的時間組成。在最簡單的配置中,你可使用數組指定值和時間。例如改變圖層的位置,你能夠經過下面的路徑改變。該動畫對象使用你指定的關鍵幀,經過在給定時間段內從一個值插值到下一個值來構建動畫。
圖 3-1 展現了一個圖層位置屬性的 5秒動畫。該位置動畫跟隨一個由 CGPathRef 數據類型指定的路徑。該動畫的代碼如例3-3所示。
例 3-3 展現了實現圖3-1 動畫的代碼。本例中的 path 對象用於定義動畫每幀的圖層位置。
例 3-3 建立彈跳關鍵幀動畫
// 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
的數據類型(如圖層的 anchorPoint
和 position
屬性),你也能夠指定一個 CGPathRef 數據類型代替。
當指定數組值時,放在數組中元素的數據類型依賴於屬性。你能夠直接添加一些對象到數組中,可是,這些對象在添加前必須轉換爲id,全部標量類型或結構都必須由對象包裝,例如:
CGRrect
類型的屬性(如 bounds
和 frame
屬性),將其包成 NSValue 對象。CATransform3D
矩陣包成 NSValue 對象。動畫該屬性會形成關鍵幀動畫將每個形變矩陣應用到圖層上。borderColor
屬性,在添加到數組以前,將每一個 CGColorRef
數據類型轉爲 id 類型。contents
屬性時,指定一個 CGImageRef
數據類型的數組。對於 CGPoint 類型的屬性,你能夠建立一個 points(包成 NSValue 的對象)的數組,或者你可使用 CGPathRef 對象去指定一個路徑去跟隨。當你指定 points 數組時,關鍵幀動畫對象在每一個連續點之間畫一條直線,並沿着該路徑執行。當你制定一個 CGPathRef 對象時,動畫在路徑的起始點開始動畫,跟隨它的輪廓,包括任何曲線。你可使用開放或者封閉路徑。
關鍵幀動畫的時間和節奏比基礎動畫更加複雜,這有幾個你可使用控制的屬性:
calculationMode
屬性定義了計算動畫時間的算法。該屬性的值影響其餘時間相關的屬性如何被使用。
calculationMode
屬性值設置爲 kCAAnimationLinear
或 kCAAnimationCubic
,它們使用提供的時間信息去生成動畫。這些模式給你動畫時間最大的控制。calculationMode
屬性值設置爲 kCAAnimationPaced
或 kCAAnimationCubicPaced
,它不依賴由 keyTimes
或 timingFunctions
屬性提供的外部時間值。時間值是被隱式計算用來提供動畫的恆定速度。calculationMode
屬性值設置爲 kCAAnimationDiscrete
,使動畫屬性在沒有任何插值的狀況下從一個關鍵幀值跳到下一個關鍵幀值。此計算模式使用 keyTimes
屬性中的值,但忽略 timingFunctions
屬性。keyTimes
屬性指定應用每一個關鍵幀值的時間標記。該屬性僅在計算模式設置爲 kCAAnimationLinear
、 kCAAnimationDiscrete
、 kCAAnimationDiscrete
的時候被使用。它不會被用於節奏動畫。
timingFunctions
屬性指定每一個關鍵幀片斷的時間曲線,該屬性會覆蓋繼承的 timingFunction
屬性。
若是你想本身處理動畫時間,使用 kCAAnimationLinear
或 kCAAnimationCubic
模式和 keyTimes
timingFunctions
屬性。keyTimes
屬性定義了應用每一個關鍵幀的時間點。全部中間值的定時由定時功能控制,容許你將 ease-in 或 ease-out 曲線應用於每一個線段。若是不指定任何定時功能,則定時是線性的。
動畫一般會執行完成,但若是須要,你也可使用下面的方法提早中止動畫:
removeAnimationForKey:
方法去移除動畫對象。該方法使用 addAnimation:forKey:
方法傳遞的 key 來識別動畫。你指定的 key 不能爲 nil。removeAllAnimations
方法。該方法會當即移除全部動畫,並使用當前的狀態信息重繪圖層。注意:你不能直接移除圖層的隱式動畫。
當你移除圖層上的動畫對象時,Core Animation 會使用圖層的當前值來重繪圖層。由於當前值一般是動畫的結束值,這會形成圖層的外觀忽然閃一下。若是你想圖層的外觀仍然保持在動畫的最後一幀上,你可使用表現樹裏的對象來獲取最後的值,而後設置在圖層樹的對象上。
關於臨時暫停動畫的更多信息,請參見暫停和重啓圖層動畫。
若是你想同時對圖層應用多個動畫,你可使用 CAAnimationGroup 對象將它們打包在一塊兒。使用組對象能夠經過提供單獨配置點來簡化多個動畫對象的管理。應用於組的時間和持續時間值會覆蓋單個動畫對象中的相同值。
例 3-4 展現了你使用組動畫來用一樣的持續時間同時執行兩個線相關(border-related)的動畫。
例 3-4 同時執行兩個動畫
// 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"];
複製代碼
一種更高級的同時執行多個動畫的方法是使用事務對象。事務 經過容許你建立內嵌動畫集合和給每一個動畫參數賦不一樣的值來提供更多的靈活性。關於如何使用事務對象,請參見顯式事務容許你改變更畫參數。
Core Animation 支持檢測動畫的開始或結束。這些通知是執行任何與動畫相關的內務處理任務的好時機。例如,你可能使用開始的通知去設置一些相關狀態信息,使用響應結束通知取消該狀態。
通知動畫狀態有兩種不一樣的方式:
setCompletionBlock:
方法在當前事務中添加一個完成塊(completion block)。當事務中全部的動畫結束時,事務會執行你的完成塊。animationDidStart:
和 animationDidStop:finished:
代理方法。若是你想將兩個動畫串在一塊兒,以實現當一個動畫結束時,另外一個動畫開始的需求。不要使用動畫通知。使用動畫對象的 beginTime
屬性在所需的時間去開始每個動畫對象。爲了將兩個動畫串在一塊兒,你能夠第一個動畫的結束時間設置爲第二個動畫的開始時間。關於動畫時間值的更多信息,請參見自定義動畫時間。
由於 iOS 的視圖底層都有圖層,因此視圖類直接從圖層對象中獲取大部分數據。所以,你在圖層上的改變也會自動反映到視圖對象上。該行爲意味着你可使用 Core Animation 或者視圖接口 的任意一種來作你的改變。
若是你想使用 Core Animation 類去初始化動畫,你必須從基於視圖的動畫塊內部發出全部 Core Animation 調用。視圖類默認禁止圖層動畫,但在動畫塊中能夠從新啓用。因此你在動畫塊外作的全部改變都是無動畫的。例 3-5 展現瞭如何隱式改變透明度和顯式的改變位置的例子。在該例中,myNewPosition 變量是在以前被計算好的,在塊中被獲取。兩個動畫在同一時間開始,可是透明度動畫在默認的時間執行,而位置動畫在動畫對象指定的時間裏執行。
例 3-5 動畫 iOS 的視圖
[UIView animateWithDuration:1.0 animations:^{
// 隱式改變 opacity
myView.layer.opacity = 0.0;
// 顯式改變 position
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"];
}];
複製代碼
動畫 OS X 上的圖層支持視圖,最好使用視圖自己的接口。你應該極少或者毫不直接修改你的圖層支持 NSView 對象的圖層。AppKit 會建立配置圖層對象,當你 app 運行時管理它們。修改圖層可能會形成視圖和圖層之間的不一樣步,這會形成意想不到的結果。對於圖層支持視圖,你的代碼必定不要修改圖層對象的如下屬性:
重要:上述限制不適用於圖層託管視圖。若是你建立了圖層對象並將其與視圖手動關聯,則你有責任修改該圖層的屬性並保持相應的視圖對象同步。
AppKit 的圖層支持視圖默認禁止隱式動畫。圖層的動畫代理對象自動爲你生效隱式動畫。若是你想直接動畫圖層的屬性,你能夠經過編碼將當前 NSAnimationContext 對象的 allowsImplicitAnimation 值改成 YES。再一次說明,你只能對除上述列表之外的屬性進行動畫。
若是你使用基於約束的佈局規則去管理你的視圖的位置,記得更新視圖約束是你動畫的一部分。在配置動畫時,必須刪除可能干擾動畫的任何約束,約束影響對視圖的位置或大小所作的任何更改。若是你正在對其中任何一個項進行動畫化更改,你能夠刪除約束,進行更改,而後應用任何須要的新約束。
有關約束以及如何使用它們來管理視圖佈局的更多信息,請參見Auto Layout 指南。