QuartzCore之CoreAnimation核心動畫介紹

1. 簡介

  • Core Animation 中文翻譯為核心動畫徘郭,它是一組非常強(qiáng)大的動畫處理API赶促,使用它能做出非常炫麗的動畫效果好芭,而且往往是事半功倍承疲。也就是說,使用少量的代碼就可以實(shí)現(xiàn)非常強(qiáng)大的功能鸥咖。
  • Core Animation的動畫執(zhí)行過程都是在后臺操作的燕鸽,不會阻塞主線程,即動畫的時候可以點(diǎn)擊(按鈕)。
  • Core Animation是直接作用在CALayer上的啼辣,并非UIView
2160098-3c1979b212c8b393.jpg

2. 核心動畫類的層次結(jié)構(gòu)

核心動畫位于CAAnimation.h中啊研,該文件提供了以下接口及類層級結(jié)構(gòu)


CAAnimation類繼承關(guān)系.jpeg

如上圖所示,CoreAnimation所使用類如下:

  • CAMediaTiming:CAAnimation實(shí)現(xiàn)的協(xié)議鸥拧,共有8個屬性控制動畫的過程党远;

  • CAAnimation:該類是所有動畫的抽象類,不能直接使用富弦,只能使用其子類沟娱。并且實(shí)現(xiàn)了CAMediaTiming協(xié)議;

  • CAPropertyAnimation:是CAAnimation的子類腕柜,支持動畫

  • CABasicAnimation:基本動畫-

  • CATransition:轉(zhuǎn)場動畫

  • CAKeyframeAnimation:關(guān)鍵幀動畫

  • CAAnimationGroup:組動畫

  • CASpringAnimation:彈簧動畫

3. CAMediaTiming協(xié)議

CAMediaTiming協(xié)議共有8個屬性济似,每個屬性簡單介紹如下

屬性 說明
duration 動畫持續(xù)時間
beginTime 動畫相對一個對象開始的時間,起到延時執(zhí)行的目的
speed 動畫執(zhí)行速度
timeOffset 動畫執(zhí)行偏移
repeatCount 動畫執(zhí)行重復(fù)次數(shù)
repeatDuration 動畫執(zhí)行時間
autoreverses 動畫結(jié)束后是否反向執(zhí)行
fillMode 決定當(dāng)前對象在非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  添加一個藍(lán)色的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)];
    
    //設(shè)置動畫持續(xù)時間
    redLayerBasicAnimation.duration = 10;

    [self.redLayer addAnimation:redLayerBasicAnimation forKey:nil];
    
    
    //給藍(lán)色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)];
   
    //設(shè)置動畫持續(xù)時間
    blueLayerBasicAnimation.duration = 5;

    [self.blueLayer addAnimation:blueLayerBasicAnimation forKey:nil];
}
@end

上述代碼在視圖上添加兩個動畫盏缤,其中一個動畫持續(xù)10s砰蠢,另一個動畫持續(xù)5秒,豎向位移為屏幕高
執(zhí)行效果如下


動畫持續(xù)時間左10右5.gif

3.2. beginTime

beginTime為相對時間系開始的時間唉铜,可以認(rèn)為是起到延時左右,設(shè)置右側(cè)藍(lán)色Layer相對當(dāng)前時間系延時5s時間執(zhí)行

    //相對于當(dāng)前時間系延后5秒台舱,起到延時作用
    blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;

執(zhí)行效果顯示藍(lán)色相對紅色延時5秒后執(zhí)行,且同時到達(dá)底


延時5秒執(zhí)行.gif

3.3. speed

speed為相對一個時間系打毛,本Layer時間流逝速度柿赊,默認(rèn)情況為1,設(shè)置藍(lán)色Layer時間流逝速度為0.5倍則在不設(shè)置時間偏移的情況下兩者同時到達(dá)低端幻枉,效果如下:

藍(lán)色Layer0.5倍流逝速度.gif

3.4. timeOffset

該屬性主要標(biāo)記一個動畫從何處執(zhí)行碰声,該屬性不存在延遲作用。例如一個動畫正常執(zhí)行如下順序:

  A   -->  B  -->  C  -->  D   -->  A

此時如果設(shè)置 timeOffset 為B狀態(tài)熬甫,則該動畫開始執(zhí)行狀態(tài)為

  B  -->  C  -->  D   -->  A  -->  B  

設(shè)置紅色動畫持續(xù)時間10s胰挑,藍(lán)色動畫持續(xù)時間5秒,設(shè)置藍(lán)色動畫的timeOffset為2.5秒

  //相對于當(dāng)前時間系延后5秒椿肩,起到延時作用
    //blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
    //設(shè)置時間流逝速度
    //blueLayerBasicAnimation.speed = 0.5;
    //設(shè)置動畫偏移時間
    blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;

運(yùn)行效果如下:


設(shè)置動畫偏移時間.gif

3.5. repeatCount

repeatCount該屬性主要記錄動畫重復(fù)持續(xù)次數(shù)瞻颂,設(shè)定紅色Layer動畫持續(xù)時間為10s,藍(lán)色為5s,新添加藍(lán)色Layer重復(fù)次數(shù)為2次,代碼如下:

blueLayerBasicAnimation.duration = 5;
    //相對于當(dāng)前時間系延后5秒郑象,起到延時作用
    //blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
    //設(shè)置時間流逝速度
    //blueLayerBasicAnimation.speed = 0.5;
    //設(shè)置動畫偏移時間
    //blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
    //設(shè)置動畫重復(fù)次數(shù)
    blueLayerBasicAnimation.repeatCount = 2;

效果如下:


藍(lán)色重復(fù)次數(shù)為2次.gif

3.6. repeatDuration

repeatDuration該屬性主要記錄動畫重復(fù)持續(xù)時間贡这,設(shè)定紅色Layer動畫持續(xù)時間為10s,藍(lán)色為5s,新添加藍(lán)色Layer動畫持續(xù)時間12.5秒,代碼如下:

     blueLayerBasicAnimation.duration = 5;
    //相對于當(dāng)前時間系延后5秒厂榛,起到延時作用
    //blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
    //設(shè)置時間流逝速度
    //blueLayerBasicAnimation.speed = 0.5;
    //設(shè)置動畫偏移時間
    //blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
    //設(shè)置動畫重復(fù)次數(shù)
    //blueLayerBasicAnimation.repeatCount = 2;
    //設(shè)置動畫持續(xù)時間
    blueLayerBasicAnimation.repeatDuration = 12.5;

運(yùn)行效果如下:


藍(lán)色持續(xù)12.5秒.gif

3.7. autoreverses

該屬性主要執(zhí)行結(jié)束動畫后是否執(zhí)行逆行動畫過程盖矫,默認(rèn)NO不執(zhí)行丽惭,如果YES則執(zhí)行,

   blueLayerBasicAnimation.duration = 5;
    //相對于當(dāng)前時間系延后5秒辈双,起到延時作用
    //blueLayerBasicAnimation.beginTime = CACurrentMediaTime()+5;
    //設(shè)置時間流逝速度
    //blueLayerBasicAnimation.speed = 0.5;
    //設(shè)置動畫偏移時間
    //blueLayerBasicAnimation.timeOffset =CACurrentMediaTime()+2.5;
    //設(shè)置動畫重復(fù)次數(shù)
    //blueLayerBasicAnimation.repeatCount = 2;
    //設(shè)置動畫持續(xù)時間
    //blueLayerBasicAnimation.repeatDuration = 12.5;
    //動畫
     blueLayerBasicAnimation.autoreverses = YES;

是否執(zhí)行逆行動畫.gif

3.8. fillMode

fillMode決定當(dāng)前對象在非active時間段的行為.比如動畫開始之前,動畫結(jié)束之后 责掏,但是該屬性要和CAAnimation中的removedOnCompletion屬性配合著使用.

/* When true, the animation is removed from the render tree once its
 * active duration has passed. Defaults to YES. */
如果是true,一旦動畫的活動期間過了湃望,那么這個動畫將被移除换衬,默認(rèn)值YES
@property(getter=isRemovedOnCompletion) BOOL removedOnCompletion;

其中fillMode屬性值(要想fillMode有效,最好設(shè)置removedOnCompletion=NO)存在四中狀態(tài)证芭,如下:

/* `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);
  • ** kCAFillModeForwards** :當(dāng)動畫結(jié)束后,layer會保持在動畫結(jié)束狀態(tài).
  • ** kCAFillModeBackwards** :當(dāng)動畫結(jié)束后,layer會一直保持著動畫最后的狀態(tài).
  • ** kCAFillModeBoth** :這個其實(shí)就是上面兩個的合成.動畫加入后開始之前,layer便處于動畫初始狀態(tài),動畫結(jié)束后layer保持動畫最后的狀
  • ** kCAFillModeRemoved** :這個是默認(rèn)值,也就是說當(dāng)動畫開始前和動畫結(jié)束后,動畫對layer都沒有影響,動畫結(jié)束后,layer會恢復(fù)到之前的狀態(tài)

測試kCAFillModeForwards狀態(tài)代碼如下:

    blueLayerBasicAnimation.fillMode = kCAFillModeForwards;
    blueLayerBasicAnimation.removedOnCompletion = NO;

運(yùn)行效果如下:


kCAFillModeForwards狀態(tài)測試.gif

4.0 CAAnimation抽象類

CAAnimation是Core Animation所有動畫類型的抽象基類瞳浦。作為一個抽象類,CAAnimation本身并沒有做多少工作檩帐,它提供了一個計(jì)時函數(shù)(用于動畫的進(jìn)入進(jìn)出狀態(tài))术幔,一個委托(用于反饋動畫狀態(tài))以及一個removedOnCompletion,用于標(biāo)識動畫是否該在結(jié)束后自動釋放(默認(rèn)YES湃密,為了防止內(nèi)存泄露)。CAAnimation同時實(shí)現(xiàn)了一些協(xié)議四敞,包括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;

4.1. +animation方法

該方法為抽象方法,由子類創(chuàng)建實(shí)例對象忿危,生成相應(yīng)的對象類型达箍。例如基本動畫、關(guān)鍵幀動畫铺厨、組動畫缎玫、轉(zhuǎn)場動畫。

4.2. timingFunction屬性

摘錄參考blog
Timing Function的會被用于變化起點(diǎn)和終點(diǎn)之間的插值計(jì)算.形象點(diǎn)說是Timing Function決定了動畫運(yùn)行的節(jié)奏(Pacing),比如是均勻變化(線性變化)解滓、先快后慢赃磨、先慢后快、還是先慢再快再慢.

時間函數(shù)是使用的一段函數(shù)來描述的,橫座標(biāo)是時間t取值范圍是0.0-1.0,縱座標(biāo)是變化量x(t)也是取值范圍也是0.0-1.0 假設(shè)有一個動畫,duration是8秒,變化值的起點(diǎn)是a終點(diǎn)是b(假設(shè)是透明度),那么在4秒處的值是多少呢洼裤? 可以通過計(jì)算為 a + x(4/8) * (b-a), 為什么這么計(jì)算呢邻辉?講實(shí)現(xiàn)的時間映射到單位值的時候4秒相對于總時間8秒就是0.5然后可以得到0.5的時候單位變化量是 x(0.5), x(0.5)/1 = 實(shí)際變化量/(b-a), 其中b-a為總變化量,所以實(shí)際變化量就是x(0.5) * (b-a) ,最后4秒時的值就是 a + x(0.5) * (b-a),所以計(jì)算的本質(zhì)是映射

Timing Function對應(yīng)的類是CAMediaTimingFunction,它提供了兩種獲得時間函數(shù)的方式,一種是使用預(yù)定義的五種時間函數(shù),一種是通過給點(diǎn)兩個控制點(diǎn)得到一個時間函數(shù). 相關(guān)的方法為

+ (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;

五種預(yù)定義的時間函數(shù)名字的常量變量分別為

  • ** ** kCAMediaTimingFunctionLinear,
  • ** **kCAMediaTimingFunctionEaseIn,
  • ** **kCAMediaTimingFunctionEaseOut,
  • ** **kCAMediaTimingFunctionEaseInEaseOut,
  • ** **kCAMediaTimingFunctionDefault.

下圖展示了前面四種Timing Function的曲線圖,橫座標(biāo)表示時間,縱座標(biāo)表示變化量,這點(diǎn)需要搞清楚(并不是平面座標(biāo)系中xy).

時間曲線.jpg

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

貝塞爾曲線.jpg

上圖中P0是起點(diǎn),P3是終點(diǎn),P1和P2是兩個控制點(diǎn)

4.3. delegate代理屬性

CAAnimation提供代理協(xié)議,代理方法提供了動畫開始和動畫結(jié)束方法腮鞍,通過代理方法執(zhí)行回調(diào)值骇。

@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

4.4. removedOnCompletion

該方法前邊已經(jīng)介紹,用于移除動畫使用

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

6.0 CABasicAnimation基礎(chǔ)動畫

CABasicAnimation 基礎(chǔ)動畫其實(shí)就是一段時間內(nèi)發(fā)生的改變,最簡單的形式就是從一個值改變到另一個值迹缀,

@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到對象當(dāng)前值之間插值

  • ** **toValue is non-nil. Interpolates between the current value of keyPath in the target layer’s presentation layer andtoValue.
    翻譯:toValue不為空匠抗,在 對象當(dāng)前值到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不為空耸采,在 對象當(dāng)前值到經(jīng)過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.
    翻譯:都不為空锣杂,在 對象以前值到對象當(dāng)前值之間插值(不懂)

7. CAKeyframeAnimation關(guān)鍵幀動畫

CAKeyframeAnimation 關(guān)鍵幀動畫未玻,該動畫從字面簡單的理解為做動畫時只需要給出動畫部分關(guān)鍵幀即可辉浦,系統(tǒng)會通過插值方式自己完成動畫颅和,在文件中存在以屬性:

/** 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

7.1 values屬性

values屬性為NSArray類型傅事,里面的元素稱為“關(guān)鍵幀”(keyframe)。動畫對象會在指定的時間(duration)內(nèi)峡扩,依次顯示values數(shù)組中的每一個關(guān)鍵幀
代碼如下:

   CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.y";
    animation.values = @[@150,@400,@100,@400];
    animation.duration = 5.f;
  
    [self.testLayer addAnimation:animation forKey:nil];

執(zhí)行動畫效果:

關(guān)鍵幀動畫.gif

7.2 keyTimes屬性

keyTimes可以為對應(yīng)的關(guān)鍵幀指定對應(yīng)的時間點(diǎn)蹭越,其取值范圍為0~1.0,keyTimes中的每一個時間值都對應(yīng)values中的每一幀教届。如果沒有設(shè)置keyTimes响鹃,各個關(guān)鍵幀的時間是平分的

keyTimes值要和運(yùn)行時間段吻合,如果不吻合會出現(xiàn)以下問題:
第一種情況:吻合情況

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.y";
    animation.values = @[@400,@0,@400,@0];//定義了4幀
    animation.duration = 5.f;
    
    //設(shè)置每一個關(guān)鍵幀的時間
    animation.keyTimes = @[@0,@(1/8.),@(3/8.),@1];
    
    [self.testLayer addAnimation:animation forKey:nil];

效果如下:

關(guān)鍵幀動畫添加keyTimes屬性.gif

分析:
添加keyTimes記錄著執(zhí)行到每一幀動畫的時間點(diǎn)案训,例如:
@400 @0 為起始值
@400 - > @0過程中买置,必須在@(1/8.)執(zhí)行到@0位置
@0 - >@400過程中,必須在@(3/8.)執(zhí)行到@ 400位置
@400 - > @0過程中强霎,必須在@1執(zhí)行到@0位置
第二種情況:少給值了忿项,少給則提前結(jié)束

 //設(shè)置每一個關(guān)鍵幀的時間
    animation.keyTimes = @[@0,@(1/8.),@1];

運(yùn)行效果:

keyTime值數(shù)量過少.gif

分析:
添加keyTimes記錄著執(zhí)行到每一幀動畫的時間點(diǎn),例如:
@400 @0 為起始值
@400 - > @0過程中城舞,必須在@(1/8.)執(zhí)行到@0位置
@0 - >@400過程中轩触,必須在@(1)執(zhí)行到@ 400位置,由于@1時間結(jié)束家夺,所以動畫直接結(jié)束

第三種情況:多給值了脱柱,則按照順序執(zhí)行,剩余時間無效

CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.y";
    animation.values = @[@400,@0,@400,@0];//定義了4幀
    animation.duration = 5.f;
    
    //設(shè)置每一個關(guān)鍵幀的時間
    animation.keyTimes = @[@0,@(1/8.),@(2/8.),@(3/8.),@(4/8.),@1];
    
    [self.testLayer addAnimation:animation forKey:nil];

效果:


keyTimes多給情況.gif

分析:
添加keyTimes記錄著執(zhí)行到每一幀動畫的時間點(diǎn)秦踪,例如:
@400 @0 為起始值
@400 - > @0過程中褐捻,必須在@(1/8.)執(zhí)行到@0位置
@0 - >@400過程中,必須在@(2/8.)執(zhí)行到@ 400位置
@400 - > @0過程中椅邓,必須在@@(3/8.)執(zhí)行到@0位置
剩余時間@(3/8.) -> @1這個時間段屬于無效冗余時間柠逞,所以動畫在等待到@1這一時刻立即結(jié)束。

7.3. timingFunctions

該屬性在上述已經(jīng)介紹過了景馁,只不過是在動畫每一個執(zhí)行路徑過程中執(zhí)行的時間類型函數(shù),如果你values個數(shù)為N板壮,則timingFunctions 個數(shù)至少為N-1;否則剩余部分則執(zhí)行線性時間函數(shù)合住。

代碼例子:

    animation.timingFunctions = @[
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];

運(yùn)行效果:

timingFunctions時間函數(shù).gif

7.4. calculationMode屬性

在關(guān)鍵幀動畫中還有一個非常重要的參數(shù),那便是calculationMode,計(jì)算模式.其主要針對的是每一幀的內(nèi)容為一個座標(biāo)點(diǎn)的情況,也就是對anchorPoint 和 position 進(jìn)行的動畫.當(dāng)在平面座標(biāo)系中有多個離散的點(diǎn)的時候,可以是離散的,也可以直線相連后進(jìn)行插值計(jì)算,也可以使用圓滑的曲線將他們相連后進(jìn)行插值計(jì)算. calculationMode目前提供如下幾種模式 kCAAnimationLinear

  • ** kCAAnimationLinear :** calculationMode的默認(rèn)值,表示當(dāng)關(guān)鍵幀為座標(biāo)點(diǎn)的時候,關(guān)鍵幀之間直接直線相連進(jìn)行插值計(jì)算;
  • ** kCAAnimationDiscrete ** 離散的,就是不進(jìn)行插值計(jì)算,所有關(guān)鍵幀直接逐個進(jìn)行顯示;
  • ** kCAAnimationPaced ** 使得動畫均勻進(jìn)行,而不是按keyTimes設(shè)置的或者按關(guān)鍵幀平分時間,此時keyTimes和timingFunctions無效;
  • ** kCAAnimationCubic ** 對關(guān)鍵幀為座標(biāo)點(diǎn)的關(guān)鍵幀進(jìn)行圓滑曲線相連后插值計(jì)算,對于曲線的形狀還可以通過tensionValues,continuityValues,biasValues來進(jìn)行調(diào)整自定義,這里的數(shù)學(xué)原理是Kochanek–Bartels spline,這里的主要目的是使得運(yùn)行的軌跡變得圓滑;
  • ** kCAAnimationCubicPaced ** 看這個名字就知道和kCAAnimationCubic有一定聯(lián)系,其實(shí)就是在kCAAnimationCubic的基礎(chǔ)上使得動畫運(yùn)行變得均勻,就是系統(tǒng)時間內(nèi)運(yùn)動的距離相同,此時keyTimes以及timingFunctions也是無效的.

對于這五種效果分別如下

1.gif

8. CAAnimationGroup組動畫

組動畫绰精,比較簡單為兩個動畫的結(jié)合體

@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

運(yùn)行效果:

組動畫.gif

9. CATransition轉(zhuǎn)場動畫


/** 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 //上下左右翻轉(zhuǎn)效果
  • suckEffect //收縮效果撒璧,如一塊布被抽走(不支持過渡方向)
  • **rippleEffect **//滴水效果(不支持過渡方向)
  • **pageCurl ** //向上翻頁效果
  • pageUnCurl //向下翻頁效果
  • **cameraIrisHollowOpen ** //相機(jī)鏡頭打開效果(不支持過渡方向)
  • cameraIrisHollowClose //相機(jī)鏡頭關(guān)上效果(不支持過渡方向)

下面看下suckEffect效果:

suckEffect.gif

9.2 subtype動畫過渡方向

規(guī)定了動畫從哪個方面過來

  • ** kCATransitionFromRightl**
  • ** kCATransitionFromLeftl**
  • ** kCATransitionFromTopl**
  • ** kCATransitionFromBottoml**

9.2 startProgress和endProgress動畫起點(diǎn)/終點(diǎn)百分比

 transition.startProgress = 0.5;

效果:

startProgress = 0.5.gif

由此可以看出:動畫初始時刻已經(jīng)執(zhí)行了0.5,所以我們看到的是執(zhí)行剩余部分的0.5部分笨使。

transition.endProgress = 0.8;

效果:

endProgress = 0.8.gif

由此可以看出:動畫在執(zhí)行到0.8進(jìn)度的時候卿樱,突然結(jié)束

10. CASpringAnimation彈簧動畫


@interface CASpringAnimation : CABasicAnimation

@property CGFloat mass;//目標(biāo)質(zhì)量
@property CGFloat stiffness;//勁度系數(shù)
@property CGFloat damping;//阻尼系數(shù)
@property CGFloat initialVelocity;//初始速度
@property(readonly) CFTimeInterval settlingDuration;//結(jié)算時間,結(jié)算時間 返回彈簧動畫到停止時的估算時間硫椰,根據(jù)當(dāng)前的動畫參數(shù)估算
通常彈簧動畫的時間使用結(jié)算時間比較準(zhǔn)確

@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;//質(zhì)量
    spring.damping = 30;//阻尼系數(shù)
    spring.stiffness = 300;//勁度系數(shù)
    spring.initialVelocity = 0;//初始化速度
    spring.duration = spring.settlingDuration;//動畫執(zhí)行時間
   
    NSLog(@"settlingDuration=%lf",spring.settlingDuration);
    [self.testLayer addAnimation:spring forKey:nil];
}

@end

運(yùn)行效果:

CASpringAnimation彈簧動畫.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末繁调,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子靶草,更是在濱河造成了極大的恐慌蹄胰,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奕翔,死亡現(xiàn)場離奇詭異裕寨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)派继,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門宾袜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驾窟,你說我怎么就攤上這事试和。” “怎么了纫普?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長好渠。 經(jīng)常有香客問我昨稼,道長,這世上最難降的妖魔是什么拳锚? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任假栓,我火速辦了婚禮,結(jié)果婚禮上霍掺,老公的妹妹穿的比我還像新娘匾荆。我一直安慰自己,他們只是感情好杆烁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布牙丽。 她就那樣靜靜地躺著,像睡著了一般兔魂。 火紅的嫁衣襯著肌膚如雪烤芦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天析校,我揣著相機(jī)與錄音构罗,去河邊找鬼铜涉。 笑死,一個胖子當(dāng)著我的面吹牛遂唧,可吹牛的內(nèi)容都是我干的芙代。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼盖彭,長吁一口氣:“原來是場噩夢啊……” “哼纹烹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起谬泌,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤滔韵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掌实,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陪蜻,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年贱鼻,在試婚紗的時候發(fā)現(xiàn)自己被綠了宴卖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡邻悬,死狀恐怖症昏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情父丰,我是刑警寧澤肝谭,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站蛾扇,受9級特大地震影響攘烛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜镀首,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一坟漱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧更哄,春花似錦芋齿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至捕传,卻和暖如春惠拭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工职辅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棒呛,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓域携,卻偏偏與公主長得像簇秒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子秀鞭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容