CABasicAnimation筆記

實(shí)例化

使用方法animationWithKeyPath:對(duì) CABasicAnimation進(jìn)行實(shí)例化,并指定Layer的屬性作為關(guān)鍵路徑進(jìn)行注冊(cè)。

//圍繞y軸旋轉(zhuǎn)
CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];

設(shè)定動(dòng)畫

設(shè)定動(dòng)畫的屬性和說明

屬性 屬性說明
duration 動(dòng)畫的時(shí)長(zhǎng)
repeatCount 重復(fù)的次數(shù)。不停重復(fù)設(shè)置為 HUGE_VALF
repeatDuration 設(shè)置動(dòng)畫的時(shí)間。在該時(shí)間內(nèi)動(dòng)畫一直執(zhí)行,不計(jì)次數(shù)。
beginTime 指定動(dòng)畫開始的時(shí)間。從開始延遲幾秒的話,設(shè)置為【CACurrentMediaTime() + 秒數(shù)】 的方式
timingFunction 設(shè)置動(dòng)畫的速度變化
autoreverses 動(dòng)畫結(jié)束時(shí)是否執(zhí)行逆動(dòng)畫
fromValue 所改變屬性的起始值
toValue 所改變屬性的結(jié)束時(shí)的值
byValue 所改變屬性相同起始值的改變量
transformAnima.fromValue = @(M_PI_2);
transformAnima.toValue = @(M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transformAnima.autoreverses = YES;
transformAnima.repeatCount = HUGE_VALF;
transformAnima.beginTime = CACurrentMediaTime() + 2;```
####防止動(dòng)畫結(jié)束后回到初始狀態(tài)
只需設(shè)置```removedOnCompletion、fillMode```兩個(gè)屬性就可以了。

transformAnima.removedOnCompletion = NO;
transformAnima.fillMode = kCAFillModeForwards;```

解釋:為什么動(dòng)畫結(jié)束后返回原狀態(tài)?首先我們需要搞明白一點(diǎn)的是,layer動(dòng)畫運(yùn)行的過程是怎樣的?其實(shí)在我們給一個(gè)視圖添加layer動(dòng)畫時(shí),真正移動(dòng)并不是我們的視圖本身,而是 presentation layer 的一個(gè)緩存。動(dòng)畫開始時(shí) presentation layer開始移動(dòng),原始layer隱藏,動(dòng)畫結(jié)束時(shí),presentation layer從屏幕上移除,原始layer顯示。這就解釋了為什么我們的視圖在動(dòng)畫結(jié)束后又回到了原來的狀態(tài),因?yàn)樗揪蜎]動(dòng)過。

這個(gè)同樣也可以解釋為什么在動(dòng)畫移動(dòng)過程中,我們?yōu)楹尾荒軐?duì)其進(jìn)行任何操作。

所以在我們完成layer動(dòng)畫之后,最好將我們的layer屬性設(shè)置為我們最終狀態(tài)的屬性,然后將presentation layer 移除掉。

添加動(dòng)畫

[self.imageView.layer addAnimation:transformAnima forKey:@"A"];```
需要注意的兩點(diǎn)
 * 一個(gè) CABasicAniamtion 的實(shí)例對(duì)象只是一個(gè)數(shù)據(jù)模型,和他綁定到哪一個(gè)layer上是沒有關(guān)系的
 *  方法`addAnimation:forKey:`是將 CABasicAniamtion 對(duì)象進(jìn)行了 copy 操作的。所以在將其添加到一個(gè)layer上之后,我們還是將其再次添加到另一個(gè)layer上的。

####fillMode屬性的理解
該屬性定義了你的動(dòng)畫在開始和結(jié)束時(shí)的動(dòng)作。默認(rèn)值是`kCAFillModeRemoved`
。
取值的解釋
 * kCAFillModeRemoved 設(shè)置為該值,動(dòng)畫將在設(shè)置的 beginTime 開始執(zhí)行(如沒有設(shè)置beginTime屬性,則動(dòng)畫立即執(zhí)行),動(dòng)畫執(zhí)行完成后將會(huì)layer的改變恢復(fù)原狀。

![](http://upload-images.jianshu.io/upload_images/701353-9687e7d2ae6922f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 * kCAFillModeForwards 設(shè)置為該值,動(dòng)畫即使之后layer的狀態(tài)將保持在動(dòng)畫的最后一幀,而removedOnCompletion的默認(rèn)屬性值是 YES,所以為了使動(dòng)畫結(jié)束之后layer保持結(jié)束狀態(tài),應(yīng)將removedOnCompletion設(shè)置為NO。

![](http://upload-images.jianshu.io/upload_images/701353-30a2dedf0702e9d2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 * kCAFillModeBackwards 設(shè)置為該值,將會(huì)立即執(zhí)行動(dòng)畫的第一幀,不論是否設(shè)置了 beginTime屬性。觀察發(fā)現(xiàn),設(shè)置該值,剛開始視圖不見,還不知道應(yīng)用在哪里。

![](http://upload-images.jianshu.io/upload_images/701353-497aa88d69466737.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 * kCAFillModeBoth 該值是 kCAFillModeForwards 和 kCAFillModeBackwards的組合狀態(tài)

![](http://upload-images.jianshu.io/upload_images/701353-f12794b16885b782.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

####Animation Easing的使用
也即是屬性`timingFunction`值的設(shè)定,有種方式來獲取屬性值

######(1)使用方法`functionWithName:`
這種方式很簡(jiǎn)單,這里只是簡(jiǎn)單說明一下取值的含義:
 * kCAMediaTimingFunctionLinear 傳這個(gè)值,在整個(gè)動(dòng)畫時(shí)間內(nèi)動(dòng)畫都是以一個(gè)相同的速度來改變。也就是勻速運(yùn)動(dòng)。

 * kCAMediaTimingFunctionEaseIn 使用該值,動(dòng)畫開始時(shí)會(huì)較慢,之后動(dòng)畫會(huì)加速。
![](http://upload-images.jianshu.io/upload_images/701353-1a1687648bfad46c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 * kCAMediaTimingFunctionEaseOut 使用該值,動(dòng)畫在開始時(shí)會(huì)較快,之后動(dòng)畫速度減慢。![](http://upload-images.jianshu.io/upload_images/701353-3390f035bf9ba315.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

 * kCAMediaTimingFunctionEaseInEaseOut 使用該值,動(dòng)畫在開始和結(jié)束時(shí)速度較慢,中間時(shí)間段內(nèi)速度較快。![](http://upload-images.jianshu.io/upload_images/701353-beadef5d454a9926.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
######(2)使用方法functionWithControlPoints: : : :實(shí)現(xiàn),這個(gè)之后再說,占個(gè)坑先。
####其他的一些設(shè)置屬性
 * repeatCount 設(shè)置動(dòng)畫的執(zhí)行次數(shù)
 * autoreverses 默認(rèn)值為 NO,將其設(shè)置為 YES
 * speed 改變動(dòng)畫的速度 可以直接設(shè)置動(dòng)畫上的speed屬性,這樣只有這個(gè)動(dòng)畫速度。

animation.speed = 2;```
或者在layer上設(shè)置speed屬性,這樣在該視圖上的所有動(dòng)畫都提速,該視圖上的所有子視圖上的動(dòng)畫也會(huì)提速。speed兩點(diǎn)需注意的:
(1) 如果設(shè)置動(dòng)畫時(shí)間為4s,speed設(shè)置為2,則動(dòng)畫只需2s即可執(zhí)行完。
(2)如果同時(shí)設(shè)置了動(dòng)畫的speed和layer 的speed,則實(shí)際的speed為兩者相乘。

使用總結(jié)

  • 在動(dòng)畫執(zhí)行完成之后,最好還是將動(dòng)畫移除掉。也就是盡量不要設(shè)置removedOnCompletion屬性為NO
  • fillMode盡量取默認(rèn)值就好了,不要去設(shè)置它的值。只有在極個(gè)別的情況下我們會(huì)修改它的值,以后會(huì)說到,這里先占個(gè)坑。
  • 解決有時(shí)視圖會(huì)閃動(dòng)一下的問題,我們可以將layer的屬性值設(shè)置為我們的動(dòng)畫最后要達(dá)到的值,然后再給我們的視圖添加layer動(dòng)畫。

例子(移動(dòng)動(dòng)畫實(shí)現(xiàn))

直接上代碼

CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.duration = 0.8;
positionAnima.fromValue = @(self.imageView.center.y);
positionAnima.toValue = @(self.imageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
positionAnima.repeatCount = HUGE_VALF;
positionAnima.repeatDuration = 2;positionAnima.removedOnCompletion = NO;
positionAnima.fillMode = kCAFillModeForwards;
[self.imageView.layer addAnimation:positionAnima forKey:@"AnimationMoveY"];

組合動(dòng)畫實(shí)現(xiàn)

CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.fromValue = @(self.imageView.center.y);
positionAnima.toValue = @(self.imageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
transformAnima.fromValue = @(0);
transformAnima.toValue = @(M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CAAnimationGroup *animaGroup = [CAAnimationGroup animation];
animaGroup.duration = 2.0f;
animaGroup.fillMode = kCAFillModeForwards;
animaGroup.removedOnCompletion = NO;
animaGroup.animations = @[positionAnima,transformAnima];[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];

獲取動(dòng)畫開始和結(jié)束時(shí)的事件

為了獲取動(dòng)畫的開始和結(jié)束事件,需要實(shí)現(xiàn)協(xié)議

positionAnima.delegate = self;```
代理方法實(shí)現(xiàn)

//動(dòng)畫開始時(shí)

  • (void)animationDidStart:(CAAnimation *)anim{
    NSLog(@"開始了");
    }
    //動(dòng)畫結(jié)束時(shí)
  • (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    //方法中的flag參數(shù)表明了動(dòng)畫是自然結(jié)束還是被打斷,比如調(diào)用了removeAnimationForKey:方法或removeAnimationForKey方法,flag為NO,如果是正常結(jié)束,flag為YES。
    NSLog(@"結(jié)束了");
    }
其實(shí)比較重要的是有多個(gè)動(dòng)畫的時(shí)候如何在代理方法中區(qū)分不同的動(dòng)畫
兩種方式

######方式一:
如果我們添加動(dòng)畫的視圖是全局變量,可使用該方法。添加動(dòng)畫時(shí),我們使用了

[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];```
所以,可根據(jù)key來區(qū)分不同的動(dòng)畫

//動(dòng)畫開始時(shí)
- (void)animationDidStart:(CAAnimation *)anim{
   if ([anim isEqual:[self.imageView.layer animationForKey:@"Animation"]]) { 
      NSLog(@"動(dòng)畫組執(zhí)行了");
   }
}
Note:把動(dòng)畫存儲(chǔ)為一個(gè)屬性然后再回調(diào)中比較,用來判定是哪個(gè)動(dòng)畫是不可行的。應(yīng)為委托傳入的動(dòng)畫參數(shù)是原始值的一個(gè)深拷貝,不是同一個(gè)值
方式二

添加動(dòng)畫的視圖是局部變量時(shí),可使用該方法
添加動(dòng)畫給動(dòng)畫設(shè)置key-value對(duì)

[positionAnima setValue:@"PositionAnima" forKey:@"AnimationKey"];
[transformAnima setValue:@"TransformAnima" forKey:@"AnimationKey"];

所以,可以根據(jù)key中不同的值來進(jìn)行區(qū)分不同的動(dòng)畫
//動(dòng)畫結(jié)束時(shí)

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"PositionAnima"]) { 
        NSLog(@"位置移動(dòng)動(dòng)畫執(zhí)行結(jié)束"); 
    } else if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"TransformAnima"]){ 
        NSLog(@"旋轉(zhuǎn)動(dòng)畫執(zhí)行結(jié)束");
    }
}

一些常用的animationWithKeyPath值的總結(jié)

說明 使用形式
transform.scale 比例轉(zhuǎn)化 @(0.8)
transform.scale.x 寬的比例 @(0.8)
transform.scale.y 高的比例 @(0.8)
transform.rotation.x 圍繞x軸旋轉(zhuǎn) @(M_PI)
transform.rotation.y 圍繞y軸旋轉(zhuǎn) @(M_PI)
transform.rotation.z 圍繞z軸旋轉(zhuǎn) @(M_PI)
cornerRadius 圓角的設(shè)置 @(50)
backgroundColor 背景顏色的變化 (id)[UIColor purpleColor].CGColor
bounds 大小,中心不變 [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)];
position 位置(中心點(diǎn)的改變) [NSValue valueWithCGPoint:CGPointMake(300, 300)];
contents 內(nèi)容,比如UIImageView的圖片 imageAnima.toValue = (id)[UIImage imageNamed:@"to"].CGImage;
opacity 透明度 @(0.7)
contentsRect.size.width 橫向拉伸縮放 @(0.4)最好是0~1之間的

特別聲明,此文章來自簡(jiǎn)書作者方方甲方方,我只是覺得收藏看起來很費(fèi)勁,所以自己摘下來學(xué)習(xí),如有打賞,我會(huì)全部打賞給原作者。

歡迎關(guān)注我的微博博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫全貌。在這里你可以看...
    F麥子閱讀 5,270評(píng)論 5 13
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫效果,實(shí)現(xiàn)這些動(dòng)畫的過程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,694評(píng)論 6 30
  • Core Animation Core Animation,中文翻譯為核心動(dòng)畫,它是一組非常強(qiáng)大的動(dòng)畫處理API,...
    45b645c5912e閱讀 3,158評(píng)論 0 21
  • 在iOS實(shí)際開發(fā)中常用的動(dòng)畫無非是以下四種:UIView動(dòng)畫,核心動(dòng)畫,幀動(dòng)畫,自定義轉(zhuǎn)場(chǎng)動(dòng)畫。 1.UIView...
    請(qǐng)叫我周小帥閱讀 3,325評(píng)論 1 23
  • 1、 一叉歐宿舍的冰箱被親切的稱謂“冰箱界的百慕大三角”。 因?yàn)槿魏文苤苯邮秤玫臇|西、或者半加工就可以吃的東西,在...
    Annie1007X閱讀 14,405評(píng)論 2 6

友情鏈接更多精彩內(nèi)容