CoreAnimation核心動畫介紹
1. 簡介
-
Core Animation,中文翻譯為核心動畫,它是一組非常強大的動畫處理API,使用它能做出非常炫麗的動畫效果,而且往往是事半功倍。也就是說,使用少量的代碼就可以實現非常強大的功能。
-
Core Animation的動畫執行過程都是在后臺操作的,不會阻塞主線程,即動畫的時候可以點擊(按鈕)。
-
要注意的是,Core Animation是直接作用在CALayer上的,并非UIView
2. 核心動畫類的層次結構
核心動畫位于CAAnimation.h中,該文件提供了以下接口及類層級結構
CAAnimation類繼承關系.jpeg
如上圖所示,CoreAnimation所使用類如下:
- CAAnimation :該類是所有動畫的抽象類,不能直接使用,只能使用其子類。并且實現了CAMediaTiming協議;
- CAPropertyAnimation :是CAAnimation的子類,支持動畫
- CAMediaTiming :CAAnimation實現的協議,共有8個屬性控制動畫的過程;
- CABasicAnimation :基本動畫-
- CATransition :轉場動畫
- CAKeyframeAnimation :關鍵幀動畫
- CAAnimationGroup :組動畫
- CASpringAnimation :彈簧動畫
3. CAMediaTiming協議
CAMediaTiming協議共有8個屬性,每個屬性簡單介紹如下
屬性 | 說明 |
---|---|
duration | 動畫持續時間 |
beginTime | 動畫相對一個對象開始的時間,起到延時執行的目的 |
speed | 動畫執行速度 |
timeOffset | 動畫執行偏移 |
repeatCount | 動畫執行重復次數 |
repeatDuration | 動畫執行時間 |
autoreverses | 動畫結束后是否反向執行 |
fillMode | 決定當前對象在非active時間段的行為 |
3.1. duration
代碼如下:
#import "ViewController.h"
define kScreenW ([UIScreen mainScreen].bounds.size.width)
define kScreenH ([UIScreen mainScreen].bounds.size.height)
@interface ViewController ()
@property (nonatomic,weak) CALayer redLayer;
@property (nonatomic,weak) CALayer blueLayer;
@end
@implementation ViewController
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//1 添加一個紅色的Layer
CALayer *redLayer = [CALayer layer];
self.redLayer = redLayer;
redLayer.backgroundColor = [UIColor redColor].CGColor;
redLayer.frame = CGRectMake(0, 0, kScreenW/2.0, 50);
[self.view.layer addSublayer:redLayer];
//1 添加一個藍色的Layer
CALayer *blueLayer =[CALayer layer];
self.blueLayer = blueLayer;
blueLayer.backgroundColor =[UIColor blueColor].CGColor;
blueLayer.frame = CGRectMake(kScreenW/2.0, 0, kScreenW/2.0, 50);
[self.view.layer addSublayer:blueLayer];
}
-(void)touchesBegan:(NSSet<UITouch > )touches withEvent:(UIEvent *)event{
//給紅色Layer添加動畫
CABasicAnimation *redLayerBasicAnimation = [CABasicAnimation animation];
redLayerBasicAnimation.keyPath=@"position";
redLayerBasicAnimation.fromValue=[NSValue valueWithCGPoint:self.redLayer.position];
redLayerBasicAnimation.toValue=[NSValue valueWithCGPoint:CGPointMake(self.redLayer.position.x, kScreenH)];
//設置動畫持續時間
redLayerBasicAnimation.duration = 10;
[self.redLayer addAnimation:redLayerBasicAnimation forKey:nil];
//給藍色Layer添加動畫
CABasicAnimation *blueLayerBasicAnimation = [CABasicAnimation animation];
blueLayerBasicAnimation.keyPath=@"position";
blueLayerBasicAnimation.fromValue=[NSValue valueWithCGPoint:self.blueLayer.position];
blueLayerBasicAnimation.toValue=[NSValue valueWithCGPoint:CGPointMake(self.blueLayer.position.x, kScreenH)];
//設置動畫持續時間
blueLayerBasicAnimation.duration = 5;
[self.blueLayer addAnimation:blueLayerBasicAnimation forKey:nil];
}
@end</code></pre>
上述代碼在視圖上添加兩個動畫,其中一個動畫持續10s,另一個動畫持續5秒,豎向位移為屏幕高
執行效果如下

動畫持續時間左10右5.gif
3.2. beginTime
beginTime為相對時間系開始的時間,可以認為是起到延時左右,設置右側藍色Layer相對當前時間系延時5s時間執行
//相對于當前時間系延后5秒,起到延時作用
blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
執行效果顯示藍色相對紅色延時5秒后執行,且同時到達底
端

延時5秒執行.gif
3.3. speed
speed為相對一個時間系,本Layer時間流逝速度,默認情況為1,設置藍色Layer時間流逝速度為0.5倍則在不設置時間偏移的情況下兩者同時到達低端,效果如下:

藍色Layer0.5倍流逝速度.gif
3.4. timeOffset
該屬性主要標記一個動畫從何處執行,該屬性不存在延遲作用。例如一個動畫正常執行如下順序:
A --> B --> C --> D --> A
此時如果設置 timeOffset 為B狀態,則該動畫開始執行狀態為
B --> C --> D --> A --> B
設置紅色動畫持續時間10s,藍色動畫持續時間5秒,設置藍色動畫的timeOffset為2.5秒
//相對于當前時間系延后5秒,起到延時作用
//blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
//設置時間流逝速度
//blueLayerBasicAnimation.speed = 0.5;
//設置動畫偏移時間
blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
運行效果如下:

設置動畫偏移時間.gif
3.5. repeatCount
repeatCount該屬性主要記錄動畫重復持續次數,設定紅色Layer動畫持續時間為10s,藍色為5s,新添加藍色Layer重復次數為2次,代碼如下:
blueLayerBasicAnimation.duration = 5;
//相對于當前時間系延后5秒,起到延時作用
//blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
//設置時間流逝速度
//blueLayerBasicAnimation.speed = 0.5;
//設置動畫偏移時間
//blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
//設置動畫重復次數
blueLayerBasicAnimation.repeatCount = 2;
效果如下:

藍色重復次數為2次.gif
3.6. repeatDuration
repeatDuration該屬性主要記錄動畫重復持續時間,設定紅色Layer動畫持續時間為10s,藍色為5s,新添加藍色Layer動畫持續時間12.5秒,代碼如下:
blueLayerBasicAnimation.duration = 5;
//相對于當前時間系延后5秒,起到延時作用
//blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
//設置時間流逝速度
//blueLayerBasicAnimation.speed = 0.5;
//設置動畫偏移時間
//blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
//設置動畫重復次數
//blueLayerBasicAnimation.repeatCount = 2;
//設置動畫持續時間
blueLayerBasicAnimation.repeatDuration = 12.5;
運行效果如下:

藍色持續12.5秒.gif
3.7. autoreverses
該屬性主要執行結束動畫后是否執行逆行動畫過程,默認NO不執行,如果YES則執行,
blueLayerBasicAnimation.duration = 5;
//相對于當前時間系延后5秒,起到延時作用
//blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
//設置時間流逝速度
//blueLayerBasicAnimation.speed = 0.5;
//設置動畫偏移時間
//blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
//設置動畫重復次數
//blueLayerBasicAnimation.repeatCount = 2;
//設置動畫持續時間
//blueLayerBasicAnimation.repeatDuration = 12.5;
//動畫
blueLayerBasicAnimation.autoreverses = YES;

是否執行逆行動畫.gif
3.8. fillMode
fillMode決定當前對象在非active時間段的行為.比如動畫開始之前,動畫結束之后 ,但是該屬性要和CAAnimation中的 removedOnCompletion 屬性配合著使用.
/* When true, the animation is removed from the render tree once its
- active duration has passed. Defaults to YES. /
如果是true,一旦動畫的活動期間過了,那么這個動畫將被移除,默認值YES
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;</code></pre>
其中fillMode屬性值(要想fillMode有效,最好設置removedOnCompletion=NO)存在四中狀態,如下:
/
`fillMode' options. */
CA_EXTERN NSString const kCAFillModeForwards
OSX_AVAILABLE_STARTING (MAC_10_5, __IPHONE_2_0);
CA_EXTERN NSString const kCAFillModeBackwards
OSX_AVAILABLE_STARTING (MAC_10_5, IPHONE_2_0);
CA_EXTERN NSString * const kCAFillModeBoth
OSX_AVAILABLE_STARTING (MAC_10_5, IPHONE_2_0);
CA_EXTERN NSString const kCAFillModeRemoved
OSX_AVAILABLE_STARTING (MAC_10_5, __IPHONE_2_0);</code></pre>
- kCAFillModeForwards :當動畫結束后,layer會保持在動畫結束狀態 .
- kCAFillModeBackwards :當動畫結束后,layer會一直保持著動畫最后的狀態.
- kCAFillModeBoth :這個其實就是上面兩個的合成.動畫加入后開始之前,layer便處于動畫初始狀態,動畫結束后layer保持動畫最后的狀
- kCAFillModeRemoved :這個是 默認值 ,也就是說當動畫開始前和動畫結束后,動畫對layer都沒有影響,動畫結束后,layer會恢復到之前的狀態
測試 kCAFillModeForwards狀態 代碼如下:
blueLayerBasicAnimation.fillMode = kCAFillModeForwards;
blueLayerBasicAnimation.removedOnCompletion = NO;
運行效果如下:

kCAFillModeForwards狀態測試.gif
4.0 CAAnimation抽象類
CAAnimation是Core Animation所有動畫類型的抽象基類。作為一個抽象類,CAAnimation本身并沒有做多少工作,它提供了一個計時函數(用于動畫的進入進出狀態),一個委托(用于反饋動畫狀態)以及一個removedOnCompletion,用于標識動畫是否該在結束后自動釋放(默認YES,為了防止內存泄露)。CAAnimation同時實現了一些協議,包括CAMediaTiming。
/
Creates a new animation object. */
- (instancetype)animation;
/* Animations implement the same property model as defined by CALayer.
- See CALayer.h for more details. */
- (nullable id)defaultValueForKey:(NSString *)key;
- (BOOL)shouldArchiveValueForKey:(NSString *)key;
/* A timing function defining the pacing of the animation. Defaults to
- nil indicating linear pacing. */
@property(nullable, strong) CAMediaTimingFunction *timingFunction;
/* The delegate of the animation. This object is retained for the
- lifetime of the animation object. Defaults to nil. See below for the
- supported delegate methods. */
@property(nullable, strong) id delegate;
/* When true, the animation is removed from the render tree once its
- active duration has passed. Defaults to YES. */
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;</code></pre>
4.1. +animation方法
該方法為抽象方法,由子類創建實例對象,生成相應的對象類型。例如基本動畫、關鍵幀動畫、組動畫、轉場動畫。
4.2. timingFunction屬性
Timing Function的會被用于變化起點和終點之間的插值計算.形象點說是Timing Function決定了動畫運行的節奏(Pacing),比如是均勻變化(線性變化)、先快后慢、先慢后快、還是先慢再快再慢.
時間函數是使用的一段函數來描述的,橫座標是時間t取值范圍是0.0-1.0,縱座標是變化量x(t)也是取值范圍也是0.0-1.0 假設有一個動畫,duration是8秒,變化值的起點是a終點是b(假設是透明度),那么在4秒處的值是多少呢? 可以通過計算為 a + x(4/8) (b-a), 為什么這么計算呢?講實現的時間映射到單位值的時候4秒相對于總時間8秒就是0.5然后可以得到0.5的時候單位變化量是 x(0.5), x(0.5)/1 = 實際變化量/(b-a), 其中b-a為總變化量,所以實際變化量就是x(0.5) (b-a) ,最后4秒時的值就是 a + x(0.5) * (b-a),所以計算的本質是映射
Timing Function對應的類是CAMediaTimingFunction,它提供了兩種獲得時間函數的方式,一種是使用預定義的五種時間函數,一種是通過給點兩個控制點得到一個時間函數. 相關的方法為
+ (instancetype)functionWithName:(NSString *)name;
(instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
(instancetype)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
(void)getControlPointAtIndex:(size_t)idx values:(float[2])ptr;</code></pre>
五種預定義的時間函數名字的常量變量分別為
- kCAMediaTimingFunctionLinear,
- kCAMediaTimingFunctionEaseIn,
- kCAMediaTimingFunctionEaseOut,
- kCAMediaTimingFunctionEaseInEaseOut,
- kCAMediaTimingFunctionDefault.
下圖展示了前面四種Timing Function的曲線圖,橫座標表示時間,縱座標表示變化量,這點需要搞清楚(并不是平面座標系中xy).

時間曲線.jpg
自定義的Timing Function的函數圖像就是一條三次 貝塞爾曲線Cubic Bezier Curve ,貝塞爾曲線的優點就是光滑,用在這里就使得變化顯得光滑.一條三次貝塞爾曲線可以由起點終點以及兩個控制點決定.
上面的kCAMediaTimingFunctionDefault對應的函數曲線其實就是通過[(0.0,0.0), (0.25,0.1), (0.25,0.1), (1.0,1.0)]這四個點決定的三次貝塞爾曲線,頭尾為起點和終點,中間的兩個點是控制點.

貝塞爾曲線.jpg
上圖中P0是起點,P3是終點,P1和P2是兩個控制點
4.3. delegate代理屬性
CAAnimation提供代理協議,代理方法提供了動畫開始和動畫結束方法,通過代理方法執行回調。
@interface NSObject (CAAnimationDelegate)
/ Called when the animation begins its active duration. /
- (void)animationDidStart:(CAAnimation *)anim;
/* Called when the animation either completes its active duration or
- is removed from the object it is attached to (i.e. the layer). 'flag'
- is true if the animation reached the end of its active duration
- without being removed. */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end</code></pre>
4.4. removedOnCompletion
該方法前邊已經介紹,用于移除動畫使用
5.0. CAPropertyAnimation
CAPropertyAnimation也是個抽象類,本身不具備動畫效果,只有子類才有,主要存在以下方法和屬性
@interface CAPropertyAnimation : CAAnimation
- (instancetype)animationWithKeyPath:(nullable NSString *)path;
@property(nullable, copy) NSString keyPath;
@property(getter=isAdditive) BOOL additive;
@property(getter=isCumulative) BOOL cumulative;
@property(nullable, strong) CAValueFunction valueFunction;
@end</code></pre>
6.0 CABasicAnimation基礎動畫
CABasicAnimation 基礎動畫其實就是一段時間內發生的改變,最簡單的形式就是從一個值改變到另一個值,
@property(nullable, strong) id fromValue;
@property(nullable, strong) id toValue;
@property(nullable, strong) id byValue;
下面這段英文摘自蘋果官方文檔,將的是fromValue toValue ByValue 怎么使用
The interpolation values are used as follows:
-
Both fromValue and toValue are non-nil. Interpolates between fromValue and toValue.
翻譯:fromValue和toValue都不為空,在fromValue到toValue之間插值
-
fromValue and byValue are non-nil. Interpolates between fromValue and (fromValue + byValue).
翻譯:fromValue和byValue都不為空,在fromValue到fromValue +byValue之間插值
- byValue and toValue are non-nil. Interpolates between (toValue - byValue) and toValue.
翻譯:byValue和toValue都不為空,在 (toValue - byValue) 到toValue之間插值
-
fromValue is non-nil. Interpolates between fromValue and the current presentation value of the property.
翻譯:fromValue不為空,在 fromValue到對象當前值之間插值
-
toValue is non-nil. Interpolates between the current value of keyPath in the target layer’s presentation layer andtoValue.
翻譯:toValue不為空,在 對象當前值到toValue之間插值
-
byValue is non-nil. Interpolates between the current value of keyPath in the target layer’s presentation layer and that value plus byValue.
翻譯:byValue不為空,在 對象當前值到經過byValue值之間插值
-
All properties are nil. Interpolates between
the previous value of keyPath in the target layer’s presentation layer and
the current value of keyPath in the target layer’s presentation layer.
翻譯:都不為空,在 對象以前值到對象當前值之間插值(不懂)
7. CAKeyframeAnimation關鍵幀動畫
CAKeyframeAnimation 關鍵幀動畫,該動畫從字面簡單的理解為做動畫時只需要給出動畫部分關鍵幀即可,系統會通過插值方式自己完成動畫,在文件中存在以屬性:
/ General keyframe animation class. /
@interface CAKeyframeAnimation : CAPropertyAnimation
@property(nullable, copy) NSArray values;
@property(nullable) CGPathRef path;
@property(nullable, copy) NSArray<NSNumber > keyTimes;
@property(nullable, copy) NSArray<CAMediaTimingFunction > timingFunctions;
@property(copy) NSString calculationMode;
@property(nullable, copy) NSArray<NSNumber > tensionValues;
@property(nullable, copy) NSArray<NSNumber > continuityValues;
@property(nullable, copy) NSArray<NSNumber > biasValues;
@property(nullable, copy) NSString *rotationMode;
@end</code></pre>
7.1 values屬性
values屬性為NSArray類型,里面的元素稱為“關鍵幀”(keyframe)。動畫對象會在指定的時間(duration)內,依次顯示values數組中的每一個關鍵幀
代碼如下:
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.y";
animation.values = @[@150,@400,@100,@400];
animation.duration = 5.f;
[self.testLayer addAnimation:animation forKey:nil];</code></pre>
執行動畫效果:

關鍵幀動畫.gif
7.2 keyTimes屬性
keyTimes可以為對應的關鍵幀指定對應的時間點,其取值范圍為0~1.0,keyTimes中的每一個時間值都對應values中的每一幀。如果沒有設置keyTimes,各個關鍵幀的時間是平分的
keyTimes值要和運行時間段吻合,如果不吻合會出現以下問題:
第一種情況:吻合情況
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.y";
animation.values = @[@400,@0,@400,@0];//定義了4幀
animation.duration = 5.f;
//設置每一個關鍵幀的時間
animation.keyTimes = @[@0,@(1/8.),@(3/8.),@1];
[self.testLayer addAnimation:animation forKey:nil];
效果如下:

關鍵幀動畫添加keyTimes屬性.gif
分析:
添加keyTimes記錄著執行到每一幀動畫的時間點,例如:
@400 @0 為起始值
@400 - > @0過程中,必須在@(1/8.)執行到@0位置
@0 - >@400過程中,必須在@(3/8.)執行到@ 400位置
@400 - > @0過程中,必須在@1執行到@0位置
第二種情況:少給值了,少給則提前結束
//設置每一個關鍵幀的時間
animation.keyTimes = @[@0,@(1/8.),@1];
運行效果:

keyTime值數量過少.gif
分析:
添加keyTimes記錄著執行到每一幀動畫的時間點,例如:
@400 @0 為起始值
@400 - > @0過程中,必須在@(1/8.)執行到@0位置
@0 - >@400過程中,必須在@(1)執行到@ 400位置,由于@1時間結束,所以動畫直接結束
第三種情況:多給值了,則按照順序執行,剩余時間無效
CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
animation.keyPath = @"position.y";
animation.values = @[@400,@0,@400,@0];//定義了4幀
animation.duration = 5.f;
//設置每一個關鍵幀的時間
animation.keyTimes = @[@0,@(1/8.),@(2/8.),@(3/8.),@(4/8.),@1];
[self.testLayer addAnimation:animation forKey:nil];
效果:

keyTimes多給情況.gif
分析:
添加keyTimes記錄著執行到每一幀動畫的時間點,例如:
@400 @0 為起始值
@400 - > @0過程中,必須在@(1/8.)執行到@0位置
@0 - >@400過程中,必須在@(2/8.)執行到@ 400位置
@400 - > @0過程中,必須在@@(3/8.)執行到@0位置
剩余時間@(3/8.) -> @1這個時間段屬于無效冗余時間,所以動畫在等待到@1這一時刻立即結束。
7.3. timingFunctions
該屬性在上述已經介紹過了,只不過是在動畫每一個執行路徑過程中執行的時間類型函數,如果你values個數為N,則timingFunctions 個數至少為N-1;否則剩余部分則執行線性時間函數。
代碼例子:
animation.timingFunctions = @[
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
運行效果:

timingFunctions時間函數.gif
7.4. calculationMode屬性
在關鍵幀動畫中還有一個非常重要的參數,那便是calculationMode,計算模式.其主要針對的是每一幀的內容為一個座標點的情況,也就是對anchorPoint 和 position 進行的動畫.當在平面座標系中有多個離散的點的時候,可以是離散的,也可以直線相連后進行插值計算,也可以使用圓滑的曲線將他們相連后進行插值計算. calculationMode目前提供如下幾種模式 kCAAnimationLinear
- kCAAnimationLinear : calculationMode的默認值,表示當關鍵幀為座標點的時候,關鍵幀之間直接直線相連進行插值計算;
- kCAAnimationDiscrete 離散的,就是不進行插值計算,所有關鍵幀直接逐個進行顯示;
- kCAAnimationPaced 使得動畫均勻進行,而不是按keyTimes設置的或者按關鍵幀平分時間,此時 keyTimes和timingFunctions無效 ;
- kCAAnimationCubic 對關鍵幀為座標點的關鍵幀進行圓滑曲線相連后插值計算,對于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進行調整自定義,這里的數學原理是Kochanek–Bartels spline,這里的主要目的是使得運行的軌跡變得圓滑;
- kCAAnimationCubicPaced 看這個名字就知道和kCAAnimationCubic有一定聯系,其實就是在kCAAnimationCubic的基礎上使得動畫運行變得均勻,就是系統時間內運動的距離相同,此時 keyTimes以及timingFunctions也是無效的 .
對于這五種效果分別如下

1.gif
8. CAAnimationGroup組動畫
組動畫,比較簡單為兩個動畫的結合體
@interface CAAnimationGroup : CAAnimation
@property(nullable, copy) NSArray<CAAnimation *> *animations;
@end
代碼如下:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,weak) CALayer *myLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *myLayer=[[CALayer alloc] init];
self.myLayer=myLayer;
myLayer.bounds=CGRectMake(0, 0, 100, 30);
myLayer.position=CGPointMake(200, 200);
myLayer.backgroundColor=[UIColor redColor].CGColor;
[self.view.layer addSublayer:myLayer];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//第一組動畫
CAKeyframeAnimation *keyframe=[CAKeyframeAnimation animationWithKeyPath:nil];
keyframe.keyPath=@"position";
UIBezierPath *path=[UIBezierPath bezierPathWithArcCenter:CGPointMake(200 , 200) radius:150 startAngle:0 endAngle:2*M_PI clockwise:YES];
keyframe.path=path.CGPath;
//第二組
CABasicAnimation *basic=[CABasicAnimation animationWithKeyPath:nil];
basic.keyPath=@"transform.rotation";
basic.byValue=@(2*M_PI *20);
//把兩組動畫組成組動畫
CAAnimationGroup *group=[[CAAnimationGroup alloc] init];
group.duration=10;
group.repeatCount=INT16_MAX;
group.animations=@[keyframe,basic];
[self.myLayer addAnimation:group forKey:nil];
}
@end
運行效果:

組動畫.gif
9. CATransition轉場動畫
/** Transition animation subclass. **/
@interface CATransition : CAAnimation
@property(copy) NSString *type;
@property(nullable, copy) NSString *subtype;
@property float startProgress;
@property float endProgress;
@property(nullable, strong) id filter;
@end
9.1 type動畫過渡類型
主要提供了4中過渡方式
- kCATransitionFade 交叉淡化過渡(不支持過渡方向)
- kCATransitionMoveIn 新視圖移到舊視圖上面
- kCATransitionPush 新視圖把舊視圖推出去
- kCATransitionReveal 將舊視圖移開,顯示下面的新視圖
私有API
- cube //立方體翻滾效果
- oglFlip //上下左右翻轉效果
- suckEffect //收縮效果,如一塊布被抽走(不支持過渡方向)
- rippleEffect //滴水效果(不支持過渡方向)
- pageCurl //向上翻頁效果
- pageUnCurl //向下翻頁效果
- cameraIrisHollowOpen //相機鏡頭打開效果(不支持過渡方向)
- cameraIrisHollowClose //相機鏡頭關上效果(不支持過渡方向)
下面看下suckEffect效果:

suckEffect.gif
9.2 subtype動畫過渡方向
規定了動畫從哪個方面過來
- kCATransitionFromRightl
- kCATransitionFromLeftl
- kCATransitionFromTopl
- kCATransitionFromBottoml
9.3 startProgress和endProgress動畫起點/終點百分比
transition.startProgress = 0.5;
效果:

startProgress = 0.5.gif
由此可以看出:動畫初始時刻已經執行了0.5,所以我們看到的是執行剩余部分的0.5部分。
transition.endProgress = 0.8;
效果:

endProgress = 0.8.gif
由此可以看出:動畫在執行到0.8進度的時候,突然結束
10. CASpringAnimation彈簧動畫
@interface CASpringAnimation : CABasicAnimation
@property CGFloat mass;//目標質量
@property CGFloat stiffness;//勁度系數
@property CGFloat damping;//阻尼系數
@property CGFloat initialVelocity;//初始速度
@property(readonly) CFTimeInterval settlingDuration;//結算時間,結算時間 返回彈簧動畫到停止時的估算時間,根據當前的動畫參數估算
通常彈簧動畫的時間使用結算時間比較準確
@end
代碼示例:
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic,strong) CALayer *testLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CALayer *testLayer = [CALayer new];
self.testLayer = testLayer;
[self.view.layer addSublayer:testLayer];
testLayer.backgroundColor = [UIColor redColor].CGColor;
testLayer.frame = CGRectMake(150, 100, 100, 100);
UIView *lineView1 = [[UIView alloc ] initWithFrame:CGRectMake(0, self.testLayer.position.y+200.0, [UIScreen mainScreen].bounds.size.width, 1)];
[self.view addSubview:lineView1];
lineView1.backgroundColor = [UIColor blueColor];
UIView *lineView2 = [[UIView alloc ] initWithFrame:CGRectMake(0, self.testLayer.position.y, [UIScreen mainScreen].bounds.size.width, 1)];
[self.view addSubview:lineView2];
lineView2.backgroundColor = [UIColor blackColor];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
CASpringAnimation *spring =[CASpringAnimation animation];
spring.keyPath = @"position.y";
spring.fromValue = @(self.testLayer.position.y);
spring.toValue = @(self.testLayer.position.y+200.0);
spring.mass = 5;//質量
spring.damping = 30;//阻尼系數
spring.stiffness = 300;//勁度系數
spring.initialVelocity = 0;//初始化速度
spring.duration = spring.settlingDuration;//動畫執行時間
NSLog(@"settlingDuration=%lf",spring.settlingDuration);
[self.testLayer addAnimation:spring forKey:nil];
}
@end
運行效果:

CASpringAnimation彈簧動畫.gif
來自:http://www.jianshu.com/p/7b8f1e00e3bd