版本記錄
| 版本號 | 時間 |
|---|---|
| V1.0 | 2017.09.23 |
前言
app中好的炫的動畫可以讓用戶耳目一新,為產(chǎn)品增色不少,關(guān)于動畫的實現(xiàn)我們可以用基本動畫、關(guān)鍵幀動畫、序列幀動畫以及基于CoreGraphic的動畫等等,接下來這幾篇我就介紹下我可以想到的幾種動畫繪制方法。具體Demo示例已開源到Github —— 刀客傳奇,感興趣的可以看我寫的另外幾篇。
1. 實現(xiàn)動畫方式深度解析(一) —— 播放GIF動畫(一)
2. 實現(xiàn)動畫方式深度解析(二) —— 播放GIF動畫之框架FLAnimatedImage的使用(二)
3. 實現(xiàn)動畫方式深度解析(三) —— 播放序列幀動畫(一)
4. 實現(xiàn)動畫方式深度解析(四) —— QuartzCore框架(一)
5. 實現(xiàn)動畫方式深度解析(五) —— QuartzCore框架之CoreAnimation(二)
6. 實現(xiàn)動畫方式深度解析(六) —— Core Animation Basics(三)
7. 實現(xiàn)動畫方式深度解析(七) —— Core Animation之Setting Up Layer Objects(四)
8. 實現(xiàn)動畫方式深度解析(八) —— Core Animation之動畫層內(nèi)容 (五)
9. 實現(xiàn)動畫方式深度解析(九) —— Core Animation之構(gòu)建圖層層級 (六)
Advanced Animation Tricks - 高級動畫技巧
有很多方法可以配置基于屬性或關(guān)鍵幀的動畫,為您做更多的事情。 需要一起或順序執(zhí)行多個動畫的應(yīng)用程序可以使用更高級的行為來同步這些動畫的時間或?qū)⑺鼈冩溄釉谝黄稹?您還可以使用其他類型的動畫對象來創(chuàng)建視覺轉(zhuǎn)換和其他有趣的動畫效果。
Transition Animations Support Changes to Layer Visibility - 轉(zhuǎn)換動畫支持更改層可見性
顧名思義,轉(zhuǎn)換動畫對象為圖層創(chuàng)建動畫視覺轉(zhuǎn)換。 過渡對象最常見的用途是以協(xié)調(diào)的方式動畫化一層的外觀和另一層的消失。 與基于屬性的動畫不同,動畫更改圖層的一個屬性,轉(zhuǎn)換動畫會操縱圖層的緩存圖像,以創(chuàng)建通過單獨更改屬性難度或不可能執(zhí)行的視覺效果。 轉(zhuǎn)換的標準類型可讓您執(zhí)行顯示,推送,移動或交叉淡入淡出動畫。 在OS X上,您還可以使用Core Image過濾器創(chuàng)建使用其他類型的效果(如擦除,卷曲,波紋或自定義效果)的轉(zhuǎn)換。
要執(zhí)行轉(zhuǎn)換動畫,您將創(chuàng)建一個CATransition對象并將其添加到轉(zhuǎn)換中涉及的層。 您可以使用轉(zhuǎn)換對象來指定要執(zhí)行的轉(zhuǎn)換類型以及轉(zhuǎn)換動畫的起點和終點。 您也不需要使用整個轉(zhuǎn)換動畫。 轉(zhuǎn)換對象允許您指定要在動畫時使用的開始和結(jié)束進度值。 這些值可讓您在其中點進行動畫開始或結(jié)束。
下面代碼顯示了用于在兩個視圖之間創(chuàng)建動畫推送轉(zhuǎn)換的代碼。 在該示例中,myView1和myView2都位于同一父視圖中的相同位置,但只有myView1當前可見。 推送過渡會導致myView1向左滑動,并且漸隱,直到它隱藏,而myView2從右側(cè)滑入并變?yōu)榭梢姟?更新兩個視圖的隱藏屬性可確保在動畫結(jié)束時兩個視圖的可視性是正確的。
//Animating a transition between two views in iOS
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.duration = 1.0;
// Add the transition animation to both layers
[myView1.layer addAnimation:transition forKey:@"transition"];
[myView2.layer addAnimation:transition forKey:@"transition"];
// Finally, change the visibility of the layers.
myView1.hidden = YES;
myView2.hidden = NO;
當同一個轉(zhuǎn)換中涉及到兩個層時,可以使用相同的轉(zhuǎn)換對象。 使用相同的轉(zhuǎn)換對象也簡化了必須編寫的代碼。 但是,您可以使用不同的轉(zhuǎn)換對象,如果每個層的轉(zhuǎn)換參數(shù)不同,那么肯定需要這樣做。
下面代碼顯示了如何使用Core Image過濾器在OS X上實現(xiàn)過渡效果。在使用所需參數(shù)配置過濾器后,將其分配給過渡對象的過濾器屬性。 之后,應(yīng)用動畫的過程與其他類型的動畫對象相同。
// Using a Core Image filter to animate a transition on OS X
// Create the Core Image filter, setting several key parameters.
CIFilter* aFilter = [CIFilter filterWithName:@"CIBarsSwipeTransition"];
[aFilter setValue:[NSNumber numberWithFloat:3.14] forKey:@"inputAngle"];
[aFilter setValue:[NSNumber numberWithFloat:30.0] forKey:@"inputWidth"];
[aFilter setValue:[NSNumber numberWithFloat:10.0] forKey:@"inputBarOffset"];
// Create the transition object
CATransition* transition = [CATransition animation];
transition.startProgress = 0;
transition.endProgress = 1.0;
transition.filter = aFilter;
transition.duration = 1.0;
[self.imageView2 setHidden:NO];
[self.imageView.layer addAnimation:transition forKey:@"transition"];
[self.imageView2.layer addAnimation:transition forKey:@"transition"];
[self.imageView setHidden:YES];
注意:在動畫中使用Core Image過濾器時,最棘手的部分是配置過濾器。 例如,使用條形滑動轉(zhuǎn)換,指定輸入角度太高或太低可能會使它看起來好像沒有轉(zhuǎn)換發(fā)生。 如果您沒有看到您想要的動畫,請嘗試將過濾器參數(shù)調(diào)整為不同的值,以查看是否更改了結(jié)果。
Customizing the Timing of an Animation - 自定義動畫的時序
Timing是動畫的重要組成部分,Core Animation可以通過CAMediaTiming協(xié)議的方法和屬性為動畫指定精確的時間信息。 兩個核心動畫類采用這個協(xié)議。 CAAnimation類采用它,以便您可以在動畫對象中指定時間信息。 CALayer還采用它,以便您可以為隱式動畫配置一些與時序相關(guān)的功能,盡管包含這些動畫的隱式事務(wù)對象通常提供優(yōu)先級的默認時序信息。
當考慮時間和動畫時,了解層對象如何隨著時間的推移是重要的。 每個層都有自己的本地時間,用于管理動畫時序。 通常,兩個不同層的本地時間足夠接近,您可以為每個層指定相同的時間值,并且用戶可能不會注意到任何內(nèi)容。 然而,層的本地時間可以由其父層或其自己的時序參數(shù)修改。 例如,更改圖層的速度屬性會導致該圖層(及其子圖層)的動畫持續(xù)時間按比例更改。
為了幫助您確定時間值適用于給定層,CALayer類定義convertTime:fromLayer:和convertTime:toLayer:方法。 您可以使用這些方法將固定時間值轉(zhuǎn)換為圖層的本地時間,或?qū)r間值從一個層轉(zhuǎn)換為另一層。 這些方法會考慮可能影響圖層本地時間的媒體時序?qū)傩?,并返回可與其他圖層一起使用的值。 下面代碼顯示了一個示例,您應(yīng)該定期使用以獲取圖層的當前本地時間。 CACurrentMediaTime函數(shù)是一個方便的函數(shù),它返回計算機的當前時鐘時間,該方法將采用該函數(shù)并將其轉(zhuǎn)換為圖層的本地時間。
// Getting a layer’s current local time
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
一旦您在圖層的本地時間中有時間值,您可以使用該值更新動畫對象或圖層的時間相關(guān)屬性。 通過這些時序?qū)傩裕梢詫崿F(xiàn)一些有趣的動畫行為,其中包括:
使用
beginTime屬性設(shè)置動畫的開始時間。 通常,動畫將在下一個更新周期開始。 您可以使用beginTime參數(shù)將動畫開始時間延遲幾秒鐘。 將兩個動畫連接在一起的方法是設(shè)置一個動畫的開始時間,以匹配另一個動畫的結(jié)束時間。如果延遲動畫的開始,您可能還需要將fillMode屬性設(shè)置為kCAFillModeBackwards。 即使圖層樹中的圖層對象包含不同的值,此填充模式也會使圖層顯示動畫的起始值。 沒有這種填充模式,您將看到在動畫開始執(zhí)行之前跳轉(zhuǎn)到最終值。 其他填充模式也可用。autoreverses屬性會使動畫在指定的持續(xù)時間內(nèi)執(zhí)行,然后返回到動畫的起始值。 您可以將此屬性與repeatCount屬性組合,以在起始值和結(jié)束值之間來回動畫。 將重復計數(shù)設(shè)置為自動轉(zhuǎn)換動畫的整數(shù)(例如1.0)會導致動畫停止其起始值。 添加額外的一半步驟(例如重復計數(shù)為1.5)會導致動畫停止其結(jié)束值。使用具有組動畫的
timeOffset屬性可以在稍后時間啟動一些動畫。
Pausing and Resuming Animations - 停止和暫停動畫
要暫停動畫,您可以利用層采用CAMediaTiming協(xié)議并將層的動畫速度設(shè)置為0.0。 將速度設(shè)置為零可暫停動畫,直到將值更改回非零值。 下面代碼顯示了如何暫停和恢復動畫的簡單示例。
// Pausing and resuming a layer’s animations
-(void)pauseLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
layer.speed = 0.0;
layer.timeOffset = pausedTime;
}
-(void)resumeLayer:(CALayer*)layer {
CFTimeInterval pausedTime = [layer timeOffset];
layer.speed = 1.0;
layer.timeOffset = 0.0;
layer.beginTime = 0.0;
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
layer.beginTime = timeSincePause;
}
Explicit Transactions Let You Change Animation Parameters - 顯式轉(zhuǎn)場讓您更改動畫參數(shù)
對圖層進行的每一次更改都必須是事務(wù)的一部分。 CATransaction類在適當?shù)臅r間管理動畫的創(chuàng)建和分組及其執(zhí)行。 在大多數(shù)情況下,您不需要創(chuàng)建自己的事務(wù)。 每當向其中一個圖層添加顯式或隱式動畫時,Core Animation將自動創(chuàng)建一個隱式事務(wù)。 但是,您也可以創(chuàng)建顯式的事務(wù)來更精確地管理這些動畫。
您可以使用CATransaction類的方法創(chuàng)建和管理事務(wù)。 開始(并隱式創(chuàng)建)一個新的事務(wù)調(diào)用begin類方法; 要結(jié)束該事務(wù),調(diào)用commit類方法。 在這些調(diào)用之間是您想成為事務(wù)一部分的更改。 例如,要更改圖層的兩個屬性,可以使用下面的代碼。
// Creating an explicit transaction
[CATransaction begin];
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransaction commit];
使用交易的主要原因之一是在顯式事務(wù)的限制內(nèi),您可以更改持續(xù)時間,計時功能和其他參數(shù)。 您還可以為整個事務(wù)分配完成塊,以便在動畫組完成時通知您的應(yīng)用。 更改動畫參數(shù)需要使用setValue:forKey:方法修改事務(wù)字典中的相應(yīng)鍵。 例如,要將默認持續(xù)時間更改為10秒,您可以更改kCATransactionAnimationDuration鍵,如下所示。
//Changing the default duration of animations
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:10.0f]
forKey:kCATransactionAnimationDuration];
// Perform the animations
[CATransaction commit];
您可以在要為不同動畫集提供不同默認值的情況下嵌套事務(wù)。 要將一個事務(wù)嵌套在另一個事務(wù)中,只需再次調(diào)用begin類方法。 每個開始調(diào)用必須通過對commit方法的相應(yīng)調(diào)用進行匹配。 只有在您提交最外層事務(wù)的更改后,Core Animation才會啟動相關(guān)聯(lián)的動畫。
下面代碼顯示了嵌套在另一個事務(wù)中的一個事務(wù)的示例。 在此示例中,內(nèi)部事務(wù)將更改與外部事務(wù)相同的動畫參數(shù),但使用不同的值。
// Nesting explicit transactions
[CATransaction begin]; // Outer transaction
// Change the animation duration to two seconds
[CATransaction setValue:[NSNumber numberWithFloat:2.0f]
forKey:kCATransactionAnimationDuration];
// Move the layer to a new position
theLayer.position = CGPointMake(0.0,0.0);
[CATransaction begin]; // Inner transaction
// Change the animation duration to five seconds
[CATransaction setValue:[NSNumber numberWithFloat:5.0f]
forKey:kCATransactionAnimationDuration];
// Change the zPosition and opacity
theLayer.zPosition=200.0;
theLayer.opacity=0.0;
[CATransaction commit]; // Inner transaction
[CATransaction commit]; // Outer transaction
Adding Perspective to Your Animations - 為您的動畫添加視覺
應(yīng)用程序可以在三個空間維度中操縱圖層,但為了簡單起見,Core Animation使用平行投影顯示圖層,這將基本上將場景平坦化為二維平面。 這種默認行為導致具有不同zPosition值的相同大小的圖層顯示為相同的大小,即使它們在z軸上相距較遠。 你通常會在三維中觀看這樣一個視角的觀點已經(jīng)消失了。 但是,您可以通過修改圖層的轉(zhuǎn)換矩陣來包含透視信息來更改該行為。
當修改場景的透視圖時,需要修改包含正在查看的圖層的超層的sublayerTransform矩陣。 修改超層通過將相同的透視信息應(yīng)用于所有子層來簡化您必須編寫的代碼。 它還確保透視圖正確應(yīng)用于在不同平面中彼此重疊的兄弟子層。
下面代碼顯示了為父層創(chuàng)建簡單透視變換的方法。 在這種情況下,自定義eyePosition變量指定沿著Z軸的相對距離以查看圖層。 通常你為eyePosition指定一個正值,以便按照預期的方式保持這些層面。 更大的值導致更平坦的場景,而較小的值會導致層之間更顯著的視覺差異。
// Adding a perspective transform to a parent layer
CATransform3D perspective = CATransform3DIdentity;
perspective.m34 = -1.0/eyePosition;
// Apply the transform to a parent layer.
myParentLayer.sublayerTransform = perspective;
配置父層后,您可以更改任何子層的zPosition屬性,并根據(jù)其距離眼睛位置的相對距離觀察其大小如何變化。
后記
未完,待續(xù)~~~
