iOS常用動(dòng)畫(huà)內(nèi)容以及原理

最近在做iOS界面轉(zhuǎn)場(chǎng)的動(dòng)畫(huà),寫(xiě)完轉(zhuǎn)場(chǎng)入口后基本元素還是回歸到我們常用的基本動(dòng)畫(huà)代碼,有關(guān)動(dòng)畫(huà)的帖子網(wǎng)絡(luò)上一搜一大把,而且介紹的都比較不錯(cuò),本文還是不厭其煩的對(duì)基本常用到的動(dòng)畫(huà)做一個(gè)詳細(xì)統(tǒng)一介紹和總結(jié),主要記錄下自己學(xué)習(xí)動(dòng)畫(huà)的點(diǎn)。

App開(kāi)發(fā)中幾乎都使用過(guò)動(dòng)畫(huà),絢麗的動(dòng)畫(huà)效果也是iOS系統(tǒng)的一大亮點(diǎn);使用動(dòng)畫(huà)可以讓我們的App非常炫酷,同時(shí)更重要的是大大的提升了用戶體驗(yàn)。那動(dòng)畫(huà)是什么呢?動(dòng)畫(huà)實(shí)質(zhì)其實(shí)就是一張張連續(xù)的圖片在一定的時(shí)間內(nèi)連續(xù)展示出來(lái)的效果。打個(gè)比方說(shuō):把很多張慢動(dòng)作的武打戲圖片連續(xù)播放合成一段小視頻。動(dòng)畫(huà)就是和這個(gè)視頻是一樣的效果!實(shí)質(zhì)就是產(chǎn)生連續(xù)的假象來(lái)欺騙人的眼睛,從而達(dá)到動(dòng)畫(huà)的效果!

iOS開(kāi)發(fā)中,常用的動(dòng)畫(huà)有UIView動(dòng)畫(huà)核心動(dòng)畫(huà),很多書(shū)籍上有區(qū)分隱式動(dòng)畫(huà)顯示動(dòng)畫(huà)以及其他動(dòng)畫(huà)的詳細(xì)介紹,下文中會(huì)簡(jiǎn)單講到,如需要詳細(xì)介紹的可以去查找下相關(guān)資料。UIView動(dòng)畫(huà)核心動(dòng)畫(huà)一圖是iOS提供的動(dòng)畫(huà)API框架結(jié)構(gòu),UIView動(dòng)畫(huà):UIKit / AppKit;核心動(dòng)畫(huà)包括:CATransaction動(dòng)畫(huà)以及Core Animation等框架,Core Animation等框架位于UIKit的下一層,相比UIView的動(dòng)畫(huà),它可以實(shí)現(xiàn)更復(fù)雜的動(dòng)畫(huà)效果。下面我們先來(lái)介紹下iOS中簡(jiǎn)單常用的UIView動(dòng)畫(huà)的內(nèi)容及其使用。

UIView動(dòng)畫(huà)和核心動(dòng)畫(huà)

Tip:在模擬器上運(yùn)行時(shí),我們可以點(diǎn)擊菜單欄Debug下的Slow Animation或者快捷鍵command+T,來(lái)放慢App中的動(dòng)畫(huà)效果并分析動(dòng)畫(huà)內(nèi)容。

一、UIView類實(shí)現(xiàn)的常用動(dòng)畫(huà)方法

對(duì)于每一個(gè)UIView都有一個(gè)Layer屬性,把這個(gè)Layer且稱作為RootLayer,而不是UIViewRootLayer的叫做非RootLayer。我們對(duì)UIView的屬性修改時(shí)時(shí)不會(huì)產(chǎn)生默認(rèn)動(dòng)畫(huà),而對(duì)非RootLayer屬性直接修改會(huì)產(chǎn)生動(dòng)畫(huà),這個(gè)默認(rèn)動(dòng)畫(huà)的時(shí)間缺省值是0.25s,這個(gè)動(dòng)畫(huà)也稱作隱式動(dòng)畫(huà)。UIView默認(rèn)情況下禁止了RootLayer的隱式動(dòng)畫(huà),但是在UIVIewanimation block方法中又重新啟用了它們。(有關(guān)UIViewCALayer介紹稍后詳說(shuō))

需要注意的是:使用UIView的動(dòng)畫(huà)方法,只能針對(duì)動(dòng)畫(huà)屬性修改才能產(chǎn)生動(dòng)畫(huà)效果。UIView支持的動(dòng)畫(huà)屬性有frameboundscentertransformalphabackgroundColorcontentStretch等。

第一種:使用UIView的 [beginAnimations … commitAniamtions] 模式來(lái)實(shí)現(xiàn)動(dòng)畫(huà)

先過(guò)一遍系統(tǒng)的API方法:

//開(kāi)始動(dòng)畫(huà)
+ (void)beginAnimations:(NSString *)animationID context:(void *)context;

//提交動(dòng)畫(huà)
+ (void)commitAnimations;

//設(shè)置動(dòng)畫(huà)代理對(duì)象
+ (void)setAnimationDelegate:(id)delegate;

//當(dāng)動(dòng)畫(huà)即將開(kāi)始時(shí)執(zhí)行指定的SEL方法《必須要先設(shè)置動(dòng)畫(huà)代理》
+ (void)setAnimationWillStartSelector:(SEL)selector

//當(dāng)動(dòng)畫(huà)結(jié)束時(shí)執(zhí)行指定的SEL方法《必須要先設(shè)置動(dòng)畫(huà)代理》
+ (void)setAnimationDidStopSelector:(SEL)selector;

//設(shè)置動(dòng)畫(huà)的持續(xù)時(shí)間,單位為:秒
+ (void)setAnimationDuration:(NSTimeInterval)duration;

//設(shè)置動(dòng)畫(huà)延遲執(zhí)行,單位為:秒
+ (void)setAnimationDelay:(NSTimeInterval)delay;

//動(dòng)畫(huà)的開(kāi)始時(shí)間,默認(rèn)為:立即
+ (void)setAnimationStartDate:(NSDate *)startDate;

//動(dòng)畫(huà)的速度曲線控制
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;

//動(dòng)畫(huà)的重復(fù)次數(shù)
+ (void)setAnimationRepeatCount:(float)repeatCount;

//如果設(shè)置為YES,代表動(dòng)畫(huà)每次重復(fù)執(zhí)行的效果會(huì)跟上一次相反
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;

//設(shè)置視圖view的過(guò)渡效果,transition指定過(guò)渡類型,cache設(shè)置YES代表使用視圖緩存,性能較好
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;

//當(dāng)設(shè)置的時(shí)候忽視所有屬性的改變
+ (void)setAnimationsEnabled:(BOOL)enabled;

這種動(dòng)畫(huà)的使用方法比較簡(jiǎn)單,將動(dòng)畫(huà)代碼寫(xiě)在begincommit之間就完成了動(dòng)畫(huà)的編寫(xiě)

[UIView beginAnimations:@"animation" context:nil]; //準(zhǔn)備動(dòng)畫(huà)
// Code... 【在此處修改view的動(dòng)畫(huà)屬性,需注意:有些屬性不支持動(dòng)畫(huà)操作的】
[UIView commitAnimations]; //提交動(dòng)畫(huà)

我們舉個(gè)簡(jiǎn)單的透明度漸變的例子:

//獲取當(dāng)前視圖的上下文,在此處傳入上下文可以在代理方法中使用到
CGContextRef context = UIGraphicsGetCurrentContext();  
//準(zhǔn)備編寫(xiě)動(dòng)畫(huà)代碼
[UIView beginAnimations:@"AlphaAnimation" context:context];
[UIView setAnimationDuration:0.5f];
[animationView setAlpha:0.0f];
[UIView commitAnimations];

第二種:使用UIView的block代碼塊調(diào)用動(dòng)畫(huà)

在iOS4的時(shí)候蘋果大量的添加了Block API,之前的動(dòng)畫(huà)API也不例外。使用動(dòng)畫(huà)的Block API后,方便了動(dòng)畫(huà)嵌套使用,也讓我們的代碼更清晰,使用也更簡(jiǎn)單了!不多說(shuō)了,下面來(lái)介紹下Block的內(nèi)容。
UIViewblock動(dòng)畫(huà)方法中常見(jiàn)的參數(shù)介紹:

duration   : 動(dòng)畫(huà)時(shí)長(zhǎng)
delay      : 決定了動(dòng)畫(huà)在延遲多久之后執(zhí)行
options    : 用來(lái)決定動(dòng)畫(huà)的展示方式,參照下面的枚舉參數(shù)說(shuō)明
animations : 具體動(dòng)畫(huà)內(nèi)容的代碼
completion : 動(dòng)畫(huà)結(jié)束后執(zhí)行的代碼塊

枚舉參數(shù)說(shuō)明:

enum {
    //這部分是基礎(chǔ)屬性的設(shè)置   
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0, //設(shè)置子視圖隨父視圖展示動(dòng)畫(huà)   
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, //允許在動(dòng)畫(huà)執(zhí)行時(shí)用戶與其進(jìn)行交互   
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, //允許在動(dòng)畫(huà)執(zhí)行時(shí)執(zhí)行新的動(dòng)畫(huà)   
    UIViewAnimationOptionRepeat                    = 1 <<  3, //設(shè)置動(dòng)畫(huà)循環(huán)執(zhí)行   
    UIViewAnimationOptionAutoreverse               = 1 <<  4, //設(shè)置動(dòng)畫(huà)反向執(zhí)行,必須和重復(fù)執(zhí)行一起使用   
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, //強(qiáng)制動(dòng)畫(huà)使用內(nèi)層動(dòng)畫(huà)的時(shí)間值
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, //強(qiáng)制動(dòng)畫(huà)使用內(nèi)層動(dòng)畫(huà)曲線值   
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, //設(shè)置動(dòng)畫(huà)視圖實(shí)時(shí)刷新
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, //設(shè)置視圖切換時(shí)隱藏,而不是移除
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9, //   
    //這部分屬性設(shè)置動(dòng)畫(huà)播放的線性效果
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16, //淡入淡出 首末減速   
    UIViewAnimationOptionCurveEaseIn               = 1 << 16, //淡入 初始減速   
    UIViewAnimationOptionCurveEaseOut              = 2 << 16, //淡出 末尾減速   
    UIViewAnimationOptionCurveLinear               = 3 << 16, //線性 勻速執(zhí)行
    //這部分設(shè)置UIView切換效果
    UIViewAnimationOptionTransitionNone            = 0 << 20,
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20, //從左邊切入   
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20, //從右邊切入   
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20, //從上面立體進(jìn)入   
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20, //從下面立體進(jìn)入   
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20, //溶解效果
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20, //從上面切入   
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20, //從下面切入
};
注意:此類型可以使用“|”進(jìn)行多項(xiàng)一起使用

①、UIView實(shí)現(xiàn)的動(dòng)畫(huà)最常用普通的方法
系統(tǒng)API的說(shuō)明和功能介紹:

//一般的動(dòng)畫(huà)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void(^)(void))animations;

常用的動(dòng)畫(huà)使用也比較簡(jiǎn)單,把之前寫(xiě)在begincommit之間的代碼移動(dòng)到block中就完成動(dòng)畫(huà)編寫(xiě),如:

[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)
                      delay:2.0 // 動(dòng)畫(huà)延遲
                    options:UIViewAnimationOptionCurveEaseIn // 動(dòng)畫(huà)過(guò)渡效果
                 animations:^{ //code... 動(dòng)畫(huà)內(nèi)容 }
                 completion:^(BOOL finished) { //code... 動(dòng)畫(huà)完成后執(zhí)行 }];

同樣的,還以透明度漸變?yōu)槔樱?/p>

[UIView animateWithDuration:0.5 // 動(dòng)畫(huà)時(shí)長(zhǎng)
                      delay:0.0 // 動(dòng)畫(huà)延遲
                    options:UIViewAnimationOptionCurveEaseIn // 動(dòng)畫(huà)過(guò)渡效果
                 animations:^{ [animationView setAlpha:0.0f]; }
                 completion:^(BOOL finished) { //code... 動(dòng)畫(huà)完成后執(zhí)行 }];

②、UIView的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)類方法
系統(tǒng)API的說(shuō)明和功能介紹:

//轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void(^)(BOOL finished))completion;
/*第二個(gè)方法調(diào)用完畢后,還需要處理View的層次關(guān)系,添加toView到父視圖并移除fromView*/

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)換個(gè)卡牌翻轉(zhuǎn)的例子,示例代碼如:

imageView.image = [UIImage imageNamed:@"背景圖片"];
[UIView transitionWithView:imageView 
                  duration:0.5 
                   options:UIViewAnimationOptionTransitionFlipFromLeft
                animations:^{ imageView.image = [UIImage imageNamed:@"內(nèi)容圖片"]; }
                completion:^(BOOL finished) { //code... 動(dòng)畫(huà)完成后執(zhí)行 }];

③、UIView的彈簧動(dòng)畫(huà)類方法(iOS 7后添加的API)
這個(gè)方法是iOS7之后的一個(gè)新方法,通過(guò)這個(gè)方法,可以方便的制作出彈簧振動(dòng)效果的動(dòng)畫(huà),這個(gè)方法的核心是兩個(gè)阻尼參數(shù)。
彈簧動(dòng)畫(huà)API的說(shuō)明和功能介紹:

//彈簧的彈性動(dòng)畫(huà)(iOS7之后新加的方法)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;

動(dòng)畫(huà)方法中的新參數(shù):

usingSpringWithDamping : 取值范圍[0.0~1.0],數(shù)值越小振動(dòng)幅度越大 
initialSpringVelocity  : 初始速度,數(shù)值越大開(kāi)始移動(dòng)越快

基本寫(xiě)法及示例代碼:

[UIView animateWithDuration:4.0 // 動(dòng)畫(huà)時(shí)長(zhǎng)                      
                      delay:0.0 // 動(dòng)畫(huà)延遲     
     usingSpringWithDamping:1.0 // 類似彈簧振動(dòng)效果 0~1      
      initialSpringVelocity:5.0 // 初始速度                    
                    options:UIViewAnimationOptionCurveEaseInOut // 動(dòng)畫(huà)過(guò)渡效果
                 animations:^{ // code... } 
                 completion:^(BOOL finished) { // code... }];

④、UIView的關(guān)鍵幀動(dòng)畫(huà)類方法(iOS 7后添加的API)
關(guān)鍵幀動(dòng)畫(huà)是指:給出整個(gè)動(dòng)畫(huà)過(guò)程中的幾個(gè)關(guān)鍵幀畫(huà)面信息,關(guān)鍵幀之間的過(guò)渡幀都由計(jì)算機(jī)自動(dòng)生成。
這個(gè)方法也是iOS7之后的一個(gè)新方法,通過(guò)這個(gè)方法可以不需要去使用到核心動(dòng)畫(huà)(Core Animation)就能創(chuàng)建關(guān)鍵幀的更多更復(fù)雜的動(dòng)畫(huà)效果。
關(guān)鍵幀動(dòng)畫(huà)API的說(shuō)明和功能介紹:

//創(chuàng)建關(guān)鍵幀方法
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void(^)(void))animations completion:(void(^)(BOOL finished))completion;

//添加關(guān)鍵幀
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void(^)(void))animations;

以簡(jiǎn)單的單次抖動(dòng)作為示例:(這寫(xiě)復(fù)雜了僅作參考)

    __weak UIView *weakView = self.animationView;
    void(^animations)(void) = ^{
        //向右旋轉(zhuǎn)
        void(^leftCallblock)(void) = ^{
            weakView.transform = CGAffineTransformRotate(weakView.transform,M_PI/9);
        };
        [UIView addKeyframeWithRelativeStartTime:0.0   //相對(duì)于6秒所開(kāi)始的時(shí)間(第0秒開(kāi)始動(dòng)畫(huà))
                                relativeDuration:1/4.0 //相對(duì)于6秒動(dòng)畫(huà)的持續(xù)時(shí)間(動(dòng)畫(huà)持續(xù)2秒)
                                      animations:leftCallblock];
        
        //復(fù)原
        void(^resetblock)(void) = ^{
            weakView.transform = CGAffineTransformIdentity;
        };
        [UIView addKeyframeWithRelativeStartTime:1/4.0   //相對(duì)于6秒所開(kāi)始的時(shí)間(第0秒開(kāi)始動(dòng)畫(huà))
                                relativeDuration:1/4.0 //相對(duì)于6秒動(dòng)畫(huà)的持續(xù)時(shí)間(動(dòng)畫(huà)持續(xù)2秒)
                                      animations:resetblock];
        
        //向左旋轉(zhuǎn)
        void(^rightCallblock)(void) = ^{
            weakView.transform = CGAffineTransformRotate(weakView.transform,-M_PI/9);
        };
        [UIView addKeyframeWithRelativeStartTime:2/4.0   //相對(duì)于6秒所開(kāi)始的時(shí)間(第0秒開(kāi)始動(dòng)畫(huà))
                                relativeDuration:1/4.0 //相對(duì)于6秒動(dòng)畫(huà)的持續(xù)時(shí)間(動(dòng)畫(huà)持續(xù)2秒)
                                      animations:rightCallblock];
        
        //復(fù)原
        [UIView addKeyframeWithRelativeStartTime:3/4.0   //相對(duì)于6秒所開(kāi)始的時(shí)間(第0秒開(kāi)始動(dòng)畫(huà))
                                relativeDuration:1/4.0 //相對(duì)于6秒動(dòng)畫(huà)的持續(xù)時(shí)間(動(dòng)畫(huà)持續(xù)2秒)
                                      animations:resetblock];
    };
    [UIView animateKeyframesWithDuration:0.5f
                                   delay:0.0f
                                 options:UIViewKeyframeAnimationOptionCalculationModeLinear
                              animations:animations
                              completion:NULL];

關(guān)鍵幀新加的枚舉參數(shù):

enum {
    UIViewKeyframeAnimationOptionCalculationModeLinear    = 0 << 10, // default 
    UIViewKeyframeAnimationOptionCalculationModeDiscrete  = 1 << 10,
    UIViewKeyframeAnimationOptionCalculationModePaced     = 2 << 10,
    UIViewKeyframeAnimationOptionCalculationModeCubic     = 3 << 10,
    UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10
};

這里的示例中使用到了transform屬性,額外再記錄下transform屬性
transform提供的API來(lái)說(shuō)主要體現(xiàn)在縮放、位移和旋轉(zhuǎn)三個(gè)方面,transform的運(yùn)算是按照矩陣(3x3矩陣)進(jìn)行運(yùn)算的,這樣會(huì)減少運(yùn)算量,提高效率。
關(guān)于transform和矩陣的詳細(xì)內(nèi)容請(qǐng)參考:iOS開(kāi)發(fā)筆記之transform

//用來(lái)連接兩個(gè)變換效果并返回。返回的t = t1 * t2
CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

//矩陣初始值。[ 1 0 0 1 0 0 ]
CGAffineTransformIdentity;

//自定義矩陣變換,需要掌握矩陣變換的知識(shí)才知道怎么用。參照上面推薦的原理鏈接
CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty);

/*
    旋轉(zhuǎn)視圖
        1.當(dāng)參數(shù)x>0 && x<=M_PI時(shí),為順時(shí)針
        2.當(dāng)參數(shù)x>-M_PI && x<0時(shí),為逆時(shí)針
        3.若參數(shù)x<M_PI || x>2.0*M_PI時(shí),則旋轉(zhuǎn)方向等同于x%2的旋轉(zhuǎn)方向
    總結(jié):旋轉(zhuǎn)方向就是向最短路徑方向旋轉(zhuǎn)
*/
CGAffineTransformMakeRotation(CGFloat angle);
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle);
?
//縮放視圖。等同于CGAffineTransformScale(self.transform, sx, sy)
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy);

//平移視圖。等同于CGAffineTransformTranslate(self.transform, tx, ty)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty);
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty);

二、核心動(dòng)畫(huà)(Core Animation框架)

Core Animation框架是基于OpenGLCore Graphics圖像處理框架的一個(gè)跨平臺(tái)的動(dòng)畫(huà)框架。在真實(shí)的開(kāi)發(fā)中,一般還是主要使用UIView封裝的動(dòng)畫(huà),而很少使用Core Animation的動(dòng)畫(huà);使用UIViewCALayer都能實(shí)現(xiàn)動(dòng)畫(huà)效果,但是當(dāng)一般的UIView動(dòng)畫(huà)不能滿足我們的需求時(shí),就需要使用核心動(dòng)畫(huà)來(lái)實(shí)現(xiàn)。核心動(dòng)畫(huà)是直接作用在CALayer上的動(dòng)畫(huà),而非UIView對(duì)象;所以介紹核心動(dòng)畫(huà)前,我們先了解下UIViewCALayer之間的聯(lián)系以及區(qū)別。

關(guān)聯(lián)引申??????????
CALayer是屬于Core Animation部分的內(nèi)容,包含在QuartzCore框架中,這是一個(gè)跨平臺(tái)的框架,既可以用在iOS中又可以用在Mac OS X中;實(shí)際上CALayer只是捕獲App所提供的內(nèi)容,并緩存成bitmap(位圖),當(dāng)任何與CALayer關(guān)聯(lián)的屬性值發(fā)生變化時(shí),Core Animation就會(huì)將新的bitmap(位圖)傳給繪圖硬件,并根據(jù)新的bitmap(位圖)更新顯示。
UIViewiOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自UIView類,它真正的繪圖部分,是由一個(gè)CALayer類來(lái)管理。每個(gè)UIView默認(rèn)就包含一個(gè)CALayer屬性,UIView就像是一個(gè)CALayer的管理器,在View顯示的時(shí)候,UIView做為CALayerCALayerDelegateUIView的顯示內(nèi)容由內(nèi)部的CALayer來(lái)顯示。訪問(wèn)UIView的與繪圖和跟坐標(biāo)有關(guān)的屬性,例如framebounds等,實(shí)際上內(nèi)部都是在訪問(wèn)它所包含的CALayer的相關(guān)屬性。有人說(shuō)UIView就像一個(gè)畫(huà)板,而layer就像畫(huà)布,一個(gè)畫(huà)板上可以有很多塊畫(huà)布,但是畫(huà)布不能有畫(huà)板。

CALayerUIView類似都擁有自己的樹(shù)形結(jié)構(gòu),UIView包含很多subView,而CALayer是可以包含subLayer的,因此形成了圖層樹(shù),CALayer層是可以嵌套的,可以向它的layer上添加subLayer,來(lái)完成某些特殊內(nèi)容的顯示。

UIViewCALayer的主要區(qū)別
1、UIView是可以響應(yīng)事件的,但是CALayer不能響應(yīng)事件
2、UIView主要負(fù)責(zé)管理顯示內(nèi)容,而CALayer主要負(fù)責(zé)渲染和呈現(xiàn)。如果沒(méi)有CALayer,我們是看不到內(nèi)容的。
3、CALayer內(nèi)部維護(hù)著三分layer tree,分別是presentLayer tree(動(dòng)畫(huà)樹(shù)),modeLayer tree(模型樹(shù)),render tree(渲染樹(shù)),在做iOS動(dòng)畫(huà)的時(shí)候,我們修改動(dòng)畫(huà)的屬性,在動(dòng)畫(huà)的其實(shí)是CALayerpresent Layer的屬性值,而最終展示在界面上的其實(shí)是提供UIViewmodelLayer

CALayer核心動(dòng)畫(huà)與UIView動(dòng)畫(huà)的區(qū)別:
UIView封裝的動(dòng)畫(huà)執(zhí)行完畢之后不會(huì)反彈,CALayer核心動(dòng)畫(huà)則會(huì);另外UIView的動(dòng)畫(huà)期間可以處理用戶事件,CALayer核心動(dòng)畫(huà)則不能。例如:如果是通過(guò)CALayer核心動(dòng)畫(huà)改變layer的位置狀態(tài),表面上看雖然已經(jīng)改變了,但是實(shí)際上它的位置是沒(méi)有改變的。

核心動(dòng)畫(huà)官方文檔地址:Core Animation Guide

核心動(dòng)畫(huà)是iOSOS X上的圖形渲染和動(dòng)畫(huà)基礎(chǔ)設(shè)施,用于為應(yīng)用程序的視圖和其他視覺(jué)元素設(shè)置動(dòng)畫(huà)。使用核心動(dòng)畫(huà),為您繪制每幅畫(huà)面所需的大部分工作。所有你需要做的是配置一些動(dòng)畫(huà)參數(shù)(如開(kāi)始和結(jié)束點(diǎn)),并告訴核心動(dòng)畫(huà)開(kāi)始。核心動(dòng)畫(huà)完成其余的工作,將大部分實(shí)際的繪圖工作交給板載圖形硬件,以加速渲染。這種自動(dòng)圖形加速可以實(shí)現(xiàn)高幀速率和平滑動(dòng)畫(huà),而不會(huì)對(duì)CPU造成負(fù)擔(dān),并減慢應(yīng)用程序的速度。

核心動(dòng)畫(huà)的繼承結(jié)構(gòu)

CAAnimation <CAMediaTiming> {
    CATransition
    CAAnimationGroup
    CAPropertyAnimation {
        CABasicAnimation {
            CASpringAnimation  (iOS 9才開(kāi)始支持)
        }
        CAKeyframeAnimation
    }
}

核心動(dòng)畫(huà)的繼承關(guān)系與常用屬性如下圖


核心動(dòng)畫(huà)的繼承關(guān)系與常用屬性

CAAnimation是所有動(dòng)畫(huà)對(duì)象的父類,它遵守CAMediaTiming協(xié)議,負(fù)責(zé)控制動(dòng)畫(huà)的時(shí)間、速度和時(shí)間曲線等等,是一個(gè)抽象類,不能直接使用。CAPropertyAnimationCAAnimation的子類,它支持動(dòng)畫(huà)地顯示圖層的KeyPath,也不能直接使用。
iOS9.0之后新增CASpringAnimation類,它實(shí)現(xiàn)彈簧效果的動(dòng)畫(huà)是CABasicAnimation的子類
綜上,核心動(dòng)畫(huà)類中可以直接使用的類有:CATransitionCABasicAnimationCASpringAnimationCAKeyframeAnimationCAAnimationGroup五個(gè)類。
①、CAAnimation的屬性介紹:注意CAAnimation不能直接使用

//動(dòng)畫(huà)開(kāi)始結(jié)束的回調(diào)代理
@property (nullable, assgin) id delegate;
//動(dòng)畫(huà)完成后是否移除動(dòng)畫(huà),默認(rèn)為YES
@property (getter=isRemovedOnCompletion) BOOL removedOnCompletion;
//動(dòng)畫(huà)的動(dòng)作規(guī)則,包含勻速、慢進(jìn)快出、快進(jìn)慢出、慢進(jìn)慢出<中間加速>、默認(rèn)
@property (nullable, strong) CAMediaTimingFunction *timingFunction;

+ (id)animation;    //類方法創(chuàng)建動(dòng)畫(huà)對(duì)象

注意:
timingFunction 可通過(guò)系統(tǒng)提供的API自定義喜歡的曲線函數(shù)來(lái)處理動(dòng)畫(huà)
動(dòng)畫(huà)的removedOnCompletion屬性需要配合fillMode來(lái)使用。默認(rèn)為YES,fillMode不可用

CAAnimation的協(xié)議屬性介紹:

//開(kāi)始時(shí)間,例如:CACurrentMediaTime() + x 其中x為延遲時(shí)間
@property CFTimeInterval beginTime;
//動(dòng)畫(huà)執(zhí)行時(shí)間,與speed有關(guān)系,默認(rèn)為1.0,如果speed=2.0,那么執(zhí)行時(shí)間為:durantion*(1.0/2.0)
@property CFTimeInterval duration;
//動(dòng)畫(huà)執(zhí)行速度
@property float speed;
//動(dòng)畫(huà)的時(shí)間延遲,默認(rèn)為0
@property CFTimeInterval timeOffset;
//重復(fù)執(zhí)行次數(shù)
@property float repeatCount;
//重復(fù)執(zhí)行時(shí)間,此屬性優(yōu)先級(jí)大于repeatCount
@property CFTimeInterval repeatDuration;
//是否自動(dòng)翻轉(zhuǎn)動(dòng)畫(huà),默認(rèn)為NO,如果為YES,那么整個(gè)動(dòng)畫(huà)效果為A->B->A
@property BOOL autoreverses;
/*動(dòng)畫(huà)的填充方式,
動(dòng)畫(huà)結(jié)束后回到準(zhǔn)備狀態(tài)(kCAFillModeForwards)、
動(dòng)畫(huà)結(jié)束后保持最后狀態(tài)(kCAFillModeBackwards)、
動(dòng)畫(huà)結(jié)束后回到準(zhǔn)備狀態(tài)并保持最后狀態(tài)(kCAFillModelBoth)、
執(zhí)行完成移除動(dòng)畫(huà)(kCAFillModeRemoved)
*/
@property (copy) NSString *fillMode;

動(dòng)畫(huà)代理對(duì)象協(xié)議

//動(dòng)畫(huà)開(kāi)始時(shí)回調(diào)此方法
- (void)animationDidStart:(CAAnimation *)animation;

//動(dòng)畫(huà)結(jié)束時(shí)回調(diào)此方法
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag;

②、CATransition轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的使用
CATransition的屬性介紹:

@property (copy) NSString *type;  //轉(zhuǎn)場(chǎng)類型
@property (nullable, copy) NSString *subtype;  //轉(zhuǎn)場(chǎng)方向
@property float startProgress;  //開(kāi)始進(jìn)度,默認(rèn)0.0,如果為0.4則直接從0.4開(kāi)始動(dòng)畫(huà)
@property float endProgress;  //結(jié)束進(jìn)度,默認(rèn)1.0,如果為0.6則直接到0.6結(jié)束動(dòng)畫(huà)
@property (nullable, strong) id filter;  //開(kāi)始進(jìn)度

轉(zhuǎn)場(chǎng)類型有私有API非私有API兩種

可供type選擇的值有以下內(nèi)容(轉(zhuǎn)場(chǎng)類型)
{
    //公開(kāi)API轉(zhuǎn)場(chǎng)種類
    kCATransitionFade      漸變
    kCATransitionMoveIn    覆蓋
    kCATransitionPush      推出
    kCATransitionReveal    揭開(kāi)
    //私有API轉(zhuǎn)場(chǎng)種類
    @"cube"                      立方體翻轉(zhuǎn)效果
    @"oglFlip"                   翻轉(zhuǎn)效果
    @"suckEffect"                收縮效果,動(dòng)畫(huà)方向不可控
    @"rippleEffect"              水滴波紋效果,動(dòng)畫(huà)方向不可控
    @"pageCurl"                  向上翻頁(yè)效果
    @"pageUnCurl"                向下翻頁(yè)效果
    @"cameralIrisHollowOpen"     攝像頭打開(kāi)效果
    @"cameralIrisHollowClose"    攝像頭關(guān)閉效果
};

可供subtype選擇的值有以下內(nèi)容(轉(zhuǎn)場(chǎng)方向)
{
    kCATransitionFromRight     從右開(kāi)始
    kCATransitionFromLeft      從左開(kāi)始
    kCATransitionFromTop       從上開(kāi)始
    kCATransitionFromBottom    從下開(kāi)始
};

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:(以淡入淡出的動(dòng)畫(huà)效果為例)

CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
animation.subType = kCATransitionFromLeft;
animation.duration = 0.5f;
self.imageView.image = [UIImage imageNamed:@"動(dòng)畫(huà)后的圖片"];
[self.imageView.layer addAnimation:animation forKey:@"transition"];

③、CAPropertyAnimation的子類CABasicAnimation的使用
CAPropertyAnimation的子類初始化方法

//通過(guò)key創(chuàng)建一個(gè)CAPropertyAnimation對(duì)象
+ (id)animationWithKeyPath:(NSString *)path;

注意:path可以設(shè)置動(dòng)畫(huà)的屬性列表
CATransform3D {
    旋轉(zhuǎn)
    rotation
    transform.rotation.x    
    transform.rotation.y
    transform.rotation.z
    縮放
    scale
    transform.scale.x        
    transform.scale.y
    transform.scale.z
    平移
    translation
    transform.translation.x    
    transform.translation.y
    transform.translation.z
}
CGPoint {
    position
    position.x
    position.y
}
CGRect {
    bounds
    bounds.size
    bounds.size.width
    bounds.size.height
    
    bounds.origin
    bounds.origin.x
    bounds.origin.y
}
property {
    opacity
    backgroundColor
    cornerRadius
    boarderWidth
    contents
    
    SHadow {
        shadowColor
        shadowOffset
        shadowOpacity
        shadowRadius
    }
}
注意:CAPropertyAnimation是抽象類,不能直接使用,只能使用子類

CABasicAnimation屬性介紹:

@property (nullable, strong) id fromValue;  //開(kāi)始值
@property (nullable, strong) id toValue;    //結(jié)束值
@property (nullable, strong) id byValue;    //偏移值

CABasicAnimation屬性之間的規(guī)則:

1、fromValue和toValue不為空,動(dòng)畫(huà)的效果會(huì)從fromValue的值變化到toValue
2、fromValue和byValue不為空,動(dòng)畫(huà)的效果將會(huì)從fromValue變化到fromValue+byValue
3、toValue和byValue都不為空,動(dòng)畫(huà)的效果將會(huì)從toValue-byValue變化到toValue
4、僅fromValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從fromValue的值變化到當(dāng)前的狀態(tài)
5、僅toValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從當(dāng)前狀態(tài)的值變化到toValue的值
6、僅byValue的值不為空,動(dòng)畫(huà)的效果將會(huì)從當(dāng)前的值變化到(當(dāng)前狀態(tài)的值+byValue)的值

CABasicAnimation動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:(以淡入淡出的動(dòng)畫(huà)效果為例)

CABasicAnimation *animation = nil;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[animation setFromValue:@1.0];
[animation setToValue:@0.1];
[animation setDelegate:self];
[animation setDuration:0.25];
[animation setRemovedOnCompletion:NO];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setAutoreverses:YES];
[animation setFillMode:kCAFillModeBoth];
[animationView.layer addAnimation:animation forKey:@"animation"];

④、CABasicAnimation的子類CASpringAnimation的使用
CASpringAnimation屬性介紹:

@property CGFloat mass;             //質(zhì)量,振幅與質(zhì)量成反比
@property CGFloat stiffness;        //剛度系數(shù),值越大,形變產(chǎn)生的力越大
@property CGFloat damping;          //阻尼系數(shù),阻止彈簧伸縮的系數(shù),值越大,停止越快
@property CGFloat initialVelocity;  //初始速率,速率為正數(shù)時(shí)速度與運(yùn)動(dòng)方向一致,為負(fù)數(shù)時(shí),速度與運(yùn)動(dòng)方向相反
@property (readonly) CFTimeInterval settlingDuration;    //結(jié)算時(shí)間,只讀。返回彈簧動(dòng)畫(huà)到停止時(shí)的估算時(shí)間

CASpringAnimation動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:

CASpringAnimation *spring = [CASpringAnimation animationWithKeyPath:@"position.y"];
spring.damping = 5;
spring.stiffness = 100;
spring.mass = 1;
spring.initialVelocity = 0;
spring.duration = spring.settlingDuration;
spring.formValue = @(animationView.cemter.y);
spring.toValue = @(animationView.center.y+(button.selected?100:-100));
spring.fillMode = kCAFillModeForwards;
[animationView.layer addAnimation:spring forKey:@"spring"];

⑤、CAPropertyAnimation的子類CAKeyframeAnimation的使用
CAKeyframeAnimation屬性介紹:

//關(guān)鍵幀值數(shù)組,一組變化值
@property (nullable, copy) NSArray *values;
//關(guān)鍵幀幀路徑,優(yōu)先級(jí)比values高
@property (nullable) CGPathRef path;
//每一幀對(duì)應(yīng)的時(shí)間,可以用來(lái)控制速度,它和每一幀對(duì)應(yīng),取值范圍:[0.0~1.0],不設(shè)置則默認(rèn)相等
@property (nullable, copy) NSArray *keyTimes;
//每一幀對(duì)應(yīng)的時(shí)間曲線函數(shù),也就是每一幀的運(yùn)動(dòng)節(jié)奏
@property (nullable, copy) NSArray *timingFunctions;
//動(dòng)畫(huà)的計(jì)算模式
@property (copy) NSString *calculationMode;
//動(dòng)畫(huà)的張力
@property (nullable, copy) NSArray *tensionValues;
//動(dòng)畫(huà)的連續(xù)性值
@property (nullable, copy) NSArray *continuityValues;
//動(dòng)畫(huà)的偏斜率
@property (nullable, copy) NSArray *biasValues;
//動(dòng)畫(huà)沿路徑旋轉(zhuǎn)方式,默認(rèn)為nil
@property (nullable, copy) NSString *rotationMode;

//動(dòng)畫(huà)的計(jì)算模式有
enum {
  kCAAnimationLinear      //默認(rèn)值,關(guān)鍵幀為座標(biāo)點(diǎn)的時(shí)候,關(guān)鍵幀之間直接直線相連進(jìn)行插值計(jì)算;
  kCAAnimationDiscrete    //離散的,也就是沒(méi)有補(bǔ)間動(dòng)畫(huà)
  kCAAnimationPaced       //平均
  kCAAnimationCubic       //對(duì)關(guān)鍵幀為座標(biāo)點(diǎn)的關(guān)鍵幀進(jìn)行圓滑曲線相連后插值計(jì)算
  kCAAnimationCubicPaced  //在kCAAnimationCubic的基礎(chǔ)上使得動(dòng)畫(huà)運(yùn)行變得均勻
};
注意:使用kCAAnimationPaced和kCAAnimationCubic以及kCAAnimationCubicPaced時(shí),keyTimes跟timeFunctions失效

//動(dòng)畫(huà)沿路徑旋轉(zhuǎn)方式
enum {
  kCAAnimationRotateAuto         //自動(dòng)旋轉(zhuǎn)
  kCAAnimationRotateAutoReverse  //自動(dòng)翻轉(zhuǎn)
};

CAKeyframeAnimation動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:

UIBezierPath *path = nil;
CAKeyframeAnimation *animation = nil;
path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 100)];
animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
[animation setPath:path.CGPath];
[animation setDuration:0.5];
[animation setRemovedOnCompletion:NO];
[animation setFillMode:kCAFillModeBoth];
[animationView.layer addAnimation:animation forKey:nil];

⑥、CAAnimationGroup的使用
CAAnimationGroup屬性介紹:

//數(shù)組中存放CAAnimation的動(dòng)畫(huà)對(duì)象
@property (nullable, copy) NSArray *animations;

CAAnimationGroup動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:

CGMutablePathRef path = CGPathCreateMutable();    
CGPathAddEllipseInRect(path, NULL, CGRectMake(0, 0, 320, 320));
CAKeyframeAnimation *position = [CAKeyframeAnimation animationWithKeyPath:@"position"];
[position setPath:path];
[position setDuration:3];
[position setRemovedOnCompletion:NO];
[position setFillMode:kCAFillModeForwards]; 
CGPathRelease(path);

CABasicAnimation *alpha = [CABasicAnimation animationWithKeyPath:@"opacity"];
[alpha setDuration:1.0];
[alpha setRepeatCount:3];
[alpha setAutoreverses:YES];
[alpha setFromValue:@1.0];
[alpha setDelegate:self];
[animation setToValue:@0.1];

CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:3.0];
[group setAnimations:@[position,alpha]];
[animationView.layer addAnimation:group forKey:nil];

三、核心動(dòng)畫(huà)和UIView動(dòng)畫(huà)的對(duì)比

核心動(dòng)畫(huà)UIView動(dòng)畫(huà)的對(duì)比:UIView動(dòng)畫(huà)可以看成是對(duì)核心動(dòng)畫(huà)的封裝,和UIView動(dòng)畫(huà)不同的是,通過(guò)核心動(dòng)畫(huà)改變layer的狀態(tài)(比如position),動(dòng)畫(huà)執(zhí)行完畢后實(shí)際上是沒(méi)有改變的(表面上看起來(lái)已改變)。
view加上動(dòng)畫(huà),本質(zhì)上是對(duì)其layer進(jìn)行操作,layer包含了各種支持動(dòng)畫(huà)的屬性,動(dòng)畫(huà)則包含了屬性變化的值、變化的速度、變化的時(shí)間等等,兩者結(jié)合產(chǎn)生動(dòng)畫(huà)的過(guò)程。
總體來(lái)說(shuō)核心動(dòng)畫(huà)的優(yōu)點(diǎn)有:
  - 性能強(qiáng)大,使用硬件加速,可以同時(shí)向多個(gè)圖層添加不同的動(dòng)畫(huà)效果
  - 接口易用,只需要少量的代碼就可以實(shí)現(xiàn)復(fù)雜的動(dòng)畫(huà)效果
  - 運(yùn)行在后臺(tái)線程中,在動(dòng)畫(huà)過(guò)程中響應(yīng)交互事件(UIView動(dòng)畫(huà)默認(rèn)動(dòng)畫(huà)過(guò)程中不響應(yīng)交互事件)

四、CATransaction的使用

CATransaction顧名思義“事務(wù)”,創(chuàng)建動(dòng)畫(huà)事務(wù)的目的是為了操作的原子性,它的目的就是能保證多個(gè)“動(dòng)畫(huà)屬性”的同時(shí)生效。它也分為隱式和顯式,在RunLoop中修改“動(dòng)畫(huà)屬性”,如果當(dāng)前沒(méi)有創(chuàng)建CATransaction,系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)CATransaction,并在當(dāng)前線程的下一個(gè)RunLoopcommit這個(gè)CATransaction,這種動(dòng)畫(huà)方式稱為隱式動(dòng)畫(huà)。使用CATransaction類中的[CATransaction begin][CATransaction commit]等相關(guān)方法創(chuàng)建的動(dòng)畫(huà)稱為顯式動(dòng)畫(huà)。顯式事務(wù)中可以定義事務(wù)中所有動(dòng)畫(huà)的運(yùn)行時(shí)間和時(shí)間函數(shù),此外,還有這個(gè)方法+ (void)setDisableActions:(BOOL)flag能顯式的關(guān)閉這個(gè)事務(wù)中的action查詢操作,關(guān)閉了查詢也就是關(guān)閉了動(dòng)畫(huà)效果,屬性值的變化就會(huì)立即生效,而沒(méi)有動(dòng)畫(huà)效果了。

關(guān)聯(lián)引申??????????
隱式動(dòng)畫(huà)的原理是:當(dāng)我們直接對(duì)可動(dòng)畫(huà)屬性賦值的時(shí)候,由于有隱式動(dòng)畫(huà)存在的可能,CALayer首先會(huì)判斷此時(shí)有沒(méi)有隱式動(dòng)畫(huà)被觸發(fā)。它會(huì)讓它的delegate(沒(méi)錯(cuò)CALayer擁有一個(gè)屬性叫做delegate)調(diào)用actionForLayer:forKey:來(lái)獲取一個(gè)返回值,這個(gè)返回值在聲明的時(shí)候是一個(gè)id對(duì)象,當(dāng)然在運(yùn)行時(shí)它可能是任何對(duì)象。這時(shí)CALayer拿到返回值,將進(jìn)行判斷:如果返回的對(duì)象是一個(gè)nil,則進(jìn)行默認(rèn)的隱式動(dòng)畫(huà);如果返回的對(duì)象是一個(gè)[NSNull null] ,則CALayer不會(huì)做任何動(dòng)畫(huà);如果是一個(gè)正確的實(shí)現(xiàn)了CAAction協(xié)議的對(duì)象,則CALayer用這個(gè)對(duì)象來(lái)生成一個(gè)CAAnimation,并加到自己身上進(jìn)行動(dòng)畫(huà)。

以重寫(xiě)的CALayer的position屬性的setter方法作例子:

- (void)setPosition:(CGPoint)position
{
    if ([self.delegate respondsToSelector:@selector(actionForLayer:forKey:)]) {
        id obj = [self.delegate actionForLayer:self forKey:@"position"];
        if (!obj) {
            // 隱式動(dòng)畫(huà)
        } else if ([obj isKindOfClass:[NSNull class]]) {
            // 直接重繪(無(wú)動(dòng)畫(huà))
        } else {
            // 使用obj生成CAAnimation
            CAAnimation * animation;
            [self addAnimation:animation forKey:nil];
        }
    }
}

CATransaction屬性介紹:

//在當(dāng)前線程開(kāi)啟一個(gè)新的事務(wù)
+ (void)begin;

//提交當(dāng)前事務(wù)期間所做的全部修改,如果不存在事務(wù)則會(huì)引發(fā)異常
+ (void)commit;

//提交一個(gè)現(xiàn)存的隱士事務(wù),將推遲提交知道實(shí)際提交嵌套的顯示事務(wù)已經(jīng)完成
+ (void)flush;

//加鎖,保證線程安全
+ (void)lock;
+ (void)unlock;

//獲取和設(shè)定事務(wù)持續(xù)時(shí)間,默認(rèn)為:0.25
+ (CFTimeInterval)animationDuration;
+ (void)setAnimationDuration:(CFTimeInterval)dur;

//暫時(shí)禁用圖層的行為
+ (BOOL)disableActions;
+ (void)setDisableActions:(BOOL)flag;

CATransaction動(dòng)畫(huà)的基本寫(xiě)法及示例代碼:

[CATransaction begin];  
[CATransaction setDisableActions:YES];  //關(guān)閉動(dòng)畫(huà)  
[CATransaction setValue:@(0.5f) forKey:kCATransactionAnimationDuration];  //動(dòng)畫(huà)時(shí)間  
animationLayer.position = CGPointMake(100, 100);  
[CATransaction commit];

注意:事務(wù)還支持嵌套,當(dāng)嵌套的時(shí)候,只有最外層的事務(wù)commit了之后,整個(gè)動(dòng)畫(huà)才會(huì)開(kāi)始。

五、UIImageView的動(dòng)畫(huà)

UIImageView的動(dòng)畫(huà)是可以讓一系列的圖片在特定的時(shí)間內(nèi)按照順序顯示。
UIImageView類中有關(guān)動(dòng)畫(huà)的屬性和方法介紹:

//動(dòng)畫(huà)普通狀態(tài)下的圖片數(shù)組
@property (nullable, nonatomic, copy) NSArray<UIImage *> *animationImages;
//動(dòng)畫(huà)高亮狀態(tài)下的圖片數(shù)組
@property (nullable, nonatomic, copy) NSArray<UIImage *> *highlightedAnimationImages;
//動(dòng)畫(huà)持續(xù)時(shí)間
@property (nonatomic) NSTimeInterval animationDuration;       
//動(dòng)畫(huà)重復(fù)次數(shù)
@property (nonatomic) NSInteger      animationRepeatCount;

- (void)startAnimating;    //開(kāi)始動(dòng)畫(huà)
- (void)stopAnimating;     //結(jié)束動(dòng)畫(huà)
- (BOOL)isAnimating;       //是否在動(dòng)畫(huà)中

UIImageView的使用方法很簡(jiǎn)單按照要求傳值即可,示例代碼:

NSArray *imagesArray = @[[UIImage imageNamed:@"image1.png"],
                         [UIImage imageNamed:@"image2.png"],
                         [UIImage imageNamed:@"image3.png"]];
UIImageView *imageView = [UIImageView alloc] init];
[imageView setFrame:CGRectMake(0, 0, 100, 100)];
imageView.animationImages = imagesArray;  //將序列幀數(shù)組賦給animationImages屬性
imageView.animationDuration = 0.25;  //設(shè)置動(dòng)畫(huà)時(shí)間
imageView.animationRepeatCount = 0;  //設(shè)置動(dòng)畫(huà)次數(shù) 0 表示無(wú)限
[self.view addSubview:imageView];
[imageView startAnimating];  //開(kāi)始播放動(dòng)畫(huà)

值得注意的地方是:圖片較少的情況,這種方法最簡(jiǎn)單實(shí)用;但如果圖片很多的話,這種方式可能會(huì)導(dǎo)致程序出現(xiàn)問(wèn)題。
UIImageView動(dòng)畫(huà)的其他缺陷是:動(dòng)畫(huà)不能夠?qū)崿F(xiàn)暫停只能停止。如有暫停的需求時(shí),用animationImages這種方式實(shí)現(xiàn)已經(jīng)不太滿足要求。我們可以使用NSTimer去實(shí)現(xiàn)UIImageViewanimation的效果,用NSTimer每隔一個(gè)時(shí)間戳去設(shè)置一次image,具體代碼如下:

//創(chuàng)建定時(shí)器定時(shí)更新圖片內(nèi)容
NSTimer *animatedTimer = [NSTimer scheduledTimerWithTimeInterval:0.04 
                                                          target:self 
                                                        selector:@selector(updateImageViewContentMethod) 
                                                        userInfo:nil 
                                                         repeats:YES];

//在定時(shí)器方法中更新圖片內(nèi)容                                                         
- (void)updateImageViewContentMethod
{
   animatedView.image = [UIImage imageNamed:[NSStringstringWithFormat:@"image%i.png",index]];
}

六、UIActivityIndicatorView的動(dòng)畫(huà)

UIActivityIndicatorView的是一個(gè)可以旋轉(zhuǎn)的進(jìn)度輪,一般用來(lái)當(dāng)loading使用。
UIActivityIndicatorView的類介紹:

//進(jìn)度輪的風(fēng)格
@property(nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
//當(dāng)動(dòng)畫(huà)停止時(shí)是否隱藏進(jìn)度輪
@property(nonatomic) BOOL                         hidesWhenStopped;
//iOS5后添加的設(shè)置進(jìn)度輪顏色的屬性
@property (nullable, readwrite, nonatomic, strong) UIColor *color;
//初始化方法
- (id)initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyle)style;
- (id)initWithFrame:(CGRect)frame;
//開(kāi)始旋轉(zhuǎn)
- (void)startAnimating;
//結(jié)束旋轉(zhuǎn)
- (void)stopAnimating;
//是否正在旋轉(zhuǎn)
- (BOOL)isAnimating;

UIActivityIndicatorView的初始化方法一般使用initWithActivityIndicatorStyle方法,UIActivityIndicatorViewStyle有三個(gè)枚舉值可供選擇:

enum {
    UIActivityIndicatorViewStyleWhiteLarge  //大型白色指示器    
    UIActivityIndicatorViewStyleWhite       //標(biāo)準(zhǔn)尺寸白色指示器    
    UIActivityIndicatorViewStyleGray        //灰色指示器,用于白色背景
};

基本使用方法及示例代碼:

UIActivityIndicatorView *animationView = nil;
animationView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
animationView.center = self.view.center;
[animationView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
[animationView setBackgroundColor:[UIColor lightGrayColor]];
[self.view addSubview:animationView];
[animationView startAnimating];

關(guān)聯(lián)引申??????????
關(guān)于另一種旋轉(zhuǎn)輪:經(jīng)常在網(wǎng)絡(luò)請(qǐng)求時(shí)狀態(tài)欄上也出現(xiàn)旋轉(zhuǎn)輪,這個(gè)是怎么添加的。具體代碼:

[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

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

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫(huà)全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,541評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫(huà)全貌。在這里你可以看...
    F麥子閱讀 5,130評(píng)論 5 13
  • 前言 本文只要描述了iOS中的Core Animation(核心動(dòng)畫(huà):隱式動(dòng)畫(huà)、顯示動(dòng)畫(huà))、貝塞爾曲線、UIVie...
    GitHubPorter閱讀 3,645評(píng)論 7 11
  • 在iOS實(shí)際開(kāi)發(fā)中常用的動(dòng)畫(huà)無(wú)非是以下四種:UIView動(dòng)畫(huà),核心動(dòng)畫(huà),幀動(dòng)畫(huà),自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。 1.UIView...
    請(qǐng)叫我周小帥閱讀 3,128評(píng)論 1 23
  • 目錄: 主要繪圖框架介紹 CALayer 繪圖 貝塞爾曲線-UIBezierPath CALayer子類 補(bǔ)充:i...
    Ryan___閱讀 1,689評(píng)論 1 9