CABasicAnimation使用總結

CABasicAnimation使用總結

實例化

使用方法animationWithKeyPath:對 CABasicAnimation進行實例化,並指定Layer的屬性做爲關鍵路徑進行註冊。緩存

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

設定動畫

設定動畫的屬性和說明動畫

屬性 說明
duration 動畫的時長
repeatCount 重複的次數。不停重複設置爲 HUGE_VALF
repeatDuration 設置動畫的時間。在該時間內動畫一直執行,不計次數。
beginTime 指定動畫開始的時間。從開始延遲幾秒的話,設置爲【CACurrentMediaTime() + 秒數】 的方式
timingFunction 設置動畫的速度變化
autoreverses 動畫結束時是否執行逆動畫
fromValue 所改變屬性的起始值
toValue 所改變屬性的結束時的值
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;

防止動畫結束後回到初始狀態

只需設置removedOnCompletionfillMode兩個屬性就能夠了。3d

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

解釋:爲何動畫結束後返回原狀態?
首先咱們須要搞明白一點的是,layer動畫運行的過程是怎樣的?其實在咱們給一個視圖添加layer動畫時,真正移動並非咱們的視圖自己,而是 presentation layer 的一個緩存。動畫開始時 presentation layer開始移動,原始layer隱藏,動畫結束時,presentation layer從屏幕上移除,原始layer顯示。這就解釋了爲何咱們的視圖在動畫結束後又回到了原來的狀態,由於它根本就沒動過。代理

這個一樣也能夠解釋爲何在動畫移動過程當中,咱們爲什麼不能對其進行任何操做。code

因此在咱們完成layer動畫以後,最好將咱們的layer屬性設置爲咱們最終狀態的屬性,而後將presentation layer 移除掉。orm

添加動畫

[self.imageView.layer addAnimation:transformAnima forKey:@"A"];

須要注意的兩點對象

  • 一個 CABasicAniamtion 的實例對象只是一個數據模型,和他綁定到哪個layer上是沒有關係的
  • 方法addAnimation:forKey:是將 CABasicAniamtion 對象進行了 copy 操做的。因此在將其添加到一個layer上以後,咱們仍是將其再次添加到另外一個layer上的。

fillMode屬性的理解

該屬性定義了你的動畫在開始和結束時的動做。默認值是 kCAFillModeRemovedblog

取值的解釋事件

  • kCAFillModeRemoved 設置爲該值,動畫將在設置的 beginTime 開始執行(如沒有設置beginTime屬性,則動畫當即執行),動畫執行完成後將會layer的改變恢復原狀。
 
 
  • kCAFillModeForwards 設置爲該值,動畫即便以後layer的狀態將保持在動畫的最後一幀,而removedOnCompletion的默認屬性值是 YES,因此爲了使動畫結束以後layer保持結束狀態,應將removedOnCompletion設置爲NO。
 
 
  • kCAFillModeBackwards 設置爲該值,將會當即執行動畫的第一幀,不管是否設置了 beginTime屬性。觀察發現,設置該值,剛開始視圖不見,還不知道應用在哪裏。
 
 
  • kCAFillModeBoth 該值是 kCAFillModeForwards 和 kCAFillModeBackwards的組合狀態
 
 

Animation Easing的使用

也便是屬性timingFunction值的設定,有種方式來獲取屬性值圖片

(1)使用方法functionWithName:

這種方式很簡單,這裏只是簡單說明一下取值的含義:

  • kCAMediaTimingFunctionLinear 傳這個值,在整個動畫時間內動畫都是以一個相同的速度來改變。也就是勻速運動。

  • kCAMediaTimingFunctionEaseIn 使用該值,動畫開始時會較慢,以後動畫會加速。


     
     
  • kCAMediaTimingFunctionEaseOut 使用該值,動畫在開始時會較快,以後動畫速度減慢。


     
     
  • kCAMediaTimingFunctionEaseInEaseOut 使用該值,動畫在開始和結束時速度較慢,中間時間段內速度較快。


     
     
(2)使用方法functionWithControlPoints: : : :實現,這個以後再說,佔個坑先。

其餘的一些設置屬性

  • repeatCount 設置動畫的執行次數
  • autoreverses 默認值爲 NO,將其設置爲 YES
  • speed 改變更畫的速度 能夠直接設置動畫上的speed屬性,這樣只有這個動畫速度。
    animation.speed = 2;
    或者在layer上設置speed屬性,這樣在該視圖上的全部動畫都提速,該視圖上的全部子視圖上的動畫也會提速。
    speed兩點需注意的:
    (1) 若是設置動畫時間爲4s,speed設置爲2,則動畫只需2s便可執行完。
    (2)若是同時設置了動畫的speed和layer 的speed,則實際的speed爲二者相乘。

使用總結

  • 在動畫執行完成以後,最好仍是將動畫移除掉。也就是儘可能不要設置removedOnCompletion屬性爲NO
  • fillMode儘可能取默認值就行了,不要去設置它的值。只有在極個別的狀況下咱們會修改它的值,之後會說到,這裏先佔個坑。
  • 解決有時視圖會閃動一下的問題,咱們能夠將layer的屬性值設置爲咱們的動畫最後要達到的值,而後再給咱們的視圖添加layer動畫。

例子(移動動畫實現)

直接上代碼

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"];

組合動畫的實現

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"];

動畫開始和結束時的事件

爲了獲取動畫的開始和結束事件,須要實現協議

positionAnima.delegate = self;

代理方法實現

//動畫開始時
- (void)animationDidStart:(CAAnimation *)anim
{
    NSLog(@"開始了");
}

//動畫結束時
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    //方法中的flag參數代表了動畫是天然結束仍是被打斷,好比調用了removeAnimationForKey:方法或removeAnimationForKey方法,flag爲NO,若是是正常結束,flag爲YES。
    NSLog(@"結束了");
}

其實比較重要的是有多個動畫的時候如何在代理方法中區分不一樣的動畫
兩種方式

方式一:

若是咱們添加動畫的視圖是全局變量,可以使用該方法。
添加動畫時,咱們使用了

[self.imageView.layer addAnimation:animaGroup forKey:@"Animation"];

因此,可根據key來區分不一樣的動畫

//動畫開始時
- (void)animationDidStart:(CAAnimation *)anim
{
    if ([anim isEqual:[self.imageView.layer animationForKey:@"Animation"]]) {
        NSLog(@"動畫組執行了");
    }
}

Note:把動畫存儲爲一個屬性而後再回調中比較,用來斷定是哪一個動畫是不可行的。應爲委託傳入的動畫參數是原始值的一個深拷貝,不是同一個值

方式二

添加動畫的視圖是局部變量時,可以使用該方法
添加動畫給動畫設置key-value對

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

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

因此,能夠根據key中不一樣的值來進行區分不一樣的動畫

//動畫結束時
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"PositionAnima"]) {
        NSLog(@"位置移動動畫執行結束");
    }
    else if ([[anim valueForKey:@"AnimationKey"]isEqualToString:@"TransformAnima"]){
        NSLog(@"旋轉動畫執行結束");
    }
}

解決循環引用問題

因爲CAAnimation的delegate使用的strong類型,

 
 

因此在全局變量以下設置時會產生循環引用的狀況

self.animation.delegate = self;//可經過複用dealloc方法來驗證

解決方案

  • 聲明一個單獨的類實現delegate的回調
//.h
#import <UIKit/UIKit.h>

@interface AnimationDelegate : NSObject

@end

//.m
#import "AnimationDelegate.h"

@implementation AnimationDelegate

- (void)animationDidStart:(CAAnimation *)anim
{
    NSLog(@"Animation Start");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"Animation Stop");
}

- (void)dealloc
{
    NSLog(@"Delegate Dealloc");
}

@end

使用方式

self.animation.delegate = [[AnimationDelegate alloc]init];
  • 使用NSProxy來解決
    該類可直接引用YYKit中的YYWeakProxy
    使用方法
self.animation.delegate = [YYWeakProxy proxyWithTarget:self];

一些經常使用的animationWithKeyPath值的總結

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