1. 程式人生 > >iOS CoreAnimation 關鍵幀動畫 CAKeyframeAnimation

iOS CoreAnimation 關鍵幀動畫 CAKeyframeAnimation

    效果:


     關鍵幀動畫, 關鍵幀動畫就是在動畫控制過程中開發者指定主要的動畫狀態, 至於各種狀態間動畫如何進行則由系統自動運算補充(每個兩個關鍵幀之間系統形成的動畫成為補間動畫), 這種動畫的好處就是開發者不用逐個每個動畫幀, 而只關心幾個關鍵幀的狀態即可

    
    關鍵幀動畫開發分為兩種形式, 一種是通過設定不同的屬性進行關鍵幀控制

另一種是通過繪製路徑進行關鍵幀控制, 後者優先順序高於前者, 如果設定了路徑則屬性就不再起作用

建立關鍵幀動畫的步驟:

// 1. 建立關鍵幀動畫
    CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    
    
    [keyAnimation setValue:[NSValue valueWithCGPoint:CGPointMake(50, 614) ]forKey:@"LayerPosition"];
    
    // 2. 設定貝塞爾曲線路徑
    CGMutablePathRef path = CGPathCreateMutable();
    // 設定易懂的起始點
    CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y);
    
    
    
    // 繪製二次貝塞爾曲線
    // 可以新增路徑,
    CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, 50, 400);
    CGPathAddCurveToPoint(path, NULL, 160, 500, -30, 600, 50, 614);
    // 給動畫新增路徑 設定路徑屬性
    keyAnimation.path = path;
    
/   // 記得釋放路徑
    CGPathRelease(path);
    
    
    keyAnimation.calculationMode = kCAAnimationCubic;
    
    // 設定動畫其他屬性
    keyAnimation.duration = 5.0;
    keyAnimation.removedOnCompletion = NO;
    keyAnimation.repeatCount = 1;
    
    keyAnimation.delegate = self;
    
    // 給圖層新增動畫
    [_layer addAnimation:keyAnimation forKey:@"KCKeyAnimation_Positon"];

關於關鍵幀動畫路徑
 
   如果路徑不是曲線的話,
    矩形路徑是從矩形的左上角開始執行, 順時針執行一週回到最上角.
    橢圓路徑的話就是從橢圓的右側開始(0度)順時針一週回到右側.

關於關鍵幀各個幀時間的屬性

keyTimes
    
    各個關鍵幀的時間控制。前面使用values設定了四個關鍵幀,預設情況下每兩幀之間的間隔為:8/(4-1)秒。如果想要控制動畫從第一幀到第二針佔用時間4秒,從第二幀到第三幀時間為2秒,而從第三幀到第四幀時間2秒的話,就可以通過keyTimes進行設定。keyTimes中儲存的是時間佔用比例點,此時可以設定keyTimes的值為0.0,0.5,0.75,1.0(當然必須轉換為NSNumber),也就是說1到2幀執行到總時間的50%,2到3幀執行到總時間的75%,3到4幀執行到8秒結束。

 caculationMode
 
    動畫計算模式。還拿上面keyValues動畫舉例,之所以1到2幀能形成連貫性動畫而不是直接從第1幀經過8/3秒到第2幀是因為動畫模式是連續的
    kCAAnimationLinear 這是計算模式的預設值
    kCAAnimationDiscrete離散的那麼你會看到動畫從第1幀經過8/3秒直接到第2幀,中間沒有任何過渡
    kCAAnimationPaced(均勻執行,會忽略keyTimes)、
    kCAAnimationCubic(平滑執行,對於位置變動關鍵幀動畫執行軌跡更平滑
    kCAAnimationCubicPaced

(平滑均勻執行)

直接上程式碼,簡單易懂, 註釋很全:

//
//  ViewController.m
//  CAKeyframeAnimation
//
//  Created by 帝炎魔 on 16/5/26.
//  Copyright © 2016年 帝炎魔. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic, strong) CALayer *layer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    // 設定背景()
    UIImage *backImage = [UIImage imageNamed:@"haha1"];
    self.view.backgroundColor = [UIColor colorWithPatternImage:backImage];
    
    // 自定義一個圖層
    _layer = [[CALayer alloc] init];
    _layer.bounds = CGRectMake(50, 50, 10, 20);
    _layer.position = CGPointMake(50, 150);
    _layer.contents = (id)[UIImage imageNamed:@"hudie"].CGImage;
    [self.view.layer addSublayer:_layer];
    
    // 建立動畫
    [self translationKeyAnimation];
}


/**
 *  關鍵幀動畫, 關鍵幀動畫就是在動畫控制過程中開發者指定主要的動畫狀態, 至於各種狀態間動畫如何進行則由系統自動運算補充(每個兩個關鍵幀之間系統形成的動畫成為補間動畫), 這種動畫的好處就是開發者不用逐個每個動畫幀, 而只關心幾個關鍵幀的狀態即可
    
    關鍵幀動畫開發分為兩種形式, 一種是通過設定不同的屬性進行關鍵幀控制
    另一種是通過繪製路徑進行關鍵幀控制, 後者優先順序高於前者, 如果設定了路徑則屬性就不再起作用

 */


/**
 *  關於關鍵幀動畫路徑
 
 *  如果路徑不是曲線的話, 
    矩形路徑是從矩形的左上角開始執行, 順時針執行一週回到最上角.
    橢圓路徑的話就是從橢圓的右側開始(0度)順時針一週回到右側.
 */

/**
 *  keyTimes
 *      
    各個關鍵幀的時間控制。前面使用values設定了四個關鍵幀,預設情況下每兩幀之間的間隔為:8/(4-1)秒。如果想要控制動畫從第一幀到第二針佔用時間4秒,從第二幀到第三幀時間為2秒,而從第三幀到第四幀時間2秒的話,就可以通過keyTimes進行設定。keyTimes中儲存的是時間佔用比例點,此時可以設定keyTimes的值為0.0,0.5,0.75,1.0(當然必須轉換為NSNumber),也就是說1到2幀執行到總時間的50%,2到3幀執行到總時間的75%,3到4幀執行到8秒結束。
 

 */


/**
 *  caculationMode
 *
 *  動畫計算模式。還拿上面keyValues動畫舉例,之所以1到2幀能形成連貫性動畫而不是直接從第1幀經過8/3秒到第2幀是因為動畫模式是連續的
    kCAAnimationLinear 這是計算模式的預設值
    kCAAnimationDiscrete離散的那麼你會看到動畫從第1幀經過8/3秒直接到第2幀,中間沒有任何過渡
    kCAAnimationPaced(均勻執行,會忽略keyTimes)、
    kCAAnimationCubic(平滑執行,對於位置變動關鍵幀動畫執行軌跡更平滑
    kCAAnimationCubicPaced(平滑均勻執行)
 */
#pragma mark --- 關鍵幀動畫----> 設定關鍵幀的點座標執行動畫路徑
- (void)translationAnimation
{
    // 1. 建立關鍵幀動畫物件  初始化keyPath
    CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    // 2.設定關鍵幀, 有4個關鍵幀
    // 對於關鍵幀動畫的初始值不能省略, 就是最少要有一個幀
    NSValue *key1 = [NSValue valueWithCGPoint:_layer.position];
    NSValue *key2 = [NSValue valueWithCGPoint:CGPointMake(80, 220)];
    NSValue *key3 = [NSValue valueWithCGPoint:CGPointMake(45, 300)];
    NSValue *key4 = [NSValue valueWithCGPoint:CGPointMake(55, 400)];
    
    // 通喲keyTimes陣列來設定關鍵幀的執行時間
    keyAnimation.keyTimes = @[@(0.1), @(0.2), @(0.3), @(1.0)];
    
    NSArray *keys = @[key1, key2, key3, key4];
    // 設定關鍵幀
    keyAnimation.values = keys;
    // 3. 設定其他屬性
    keyAnimation.duration = 5.0;
    keyAnimation.repeatCount = HUGE_VALF;
    keyAnimation.removedOnCompletion = NO;
    
    // 設定動畫的開始時間 延時兩秒執行
    keyAnimation.beginTime = CACurrentMediaTime() + 2;
    
    // 4.給圖層新增動畫
    [_layer addAnimation:keyAnimation forKey:@"KCKeyframeAnimation_Position"];
    
}


#pragma mark ---- 關鍵幀動畫 ----> 設定貝塞爾曲線作為動畫執行的路徑
- (void)translationKeyAnimation
{
    // 1. 建立關鍵幀動畫
    CAKeyframeAnimation *keyAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    
    
    [keyAnimation setValue:[NSValue valueWithCGPoint:CGPointMake(50, 614) ]forKey:@"LayerPosition"];
    
    // 2. 設定貝塞爾曲線路徑
    CGMutablePathRef path = CGPathCreateMutable();
    // 設定易懂的起始點
    CGPathMoveToPoint(path, NULL, _layer.position.x, _layer.position.y);
    
    
    
    // 繪製二次貝塞爾曲線
    // 可以新增路徑,
    CGPathAddCurveToPoint(path, NULL, 160, 280, -30, 300, 50, 400);
    CGPathAddCurveToPoint(path, NULL, 160, 500, -30, 600, 50, 614);
    // 給動畫新增路徑 設定路徑屬性
    keyAnimation.path = path;
    
    CGPathRelease(path);
    
    
    keyAnimation.calculationMode = kCAAnimationCubic;
    
    // 設定動畫其他屬性
    keyAnimation.duration = 5.0;
    keyAnimation.removedOnCompletion = NO;
    keyAnimation.repeatCount = 1;
    
    keyAnimation.delegate = self;
    
    // 給圖層新增動畫
    [_layer addAnimation:keyAnimation forKey:@"KCKeyAnimation_Positon"];
}

#pragma mark --- 動畫的代理方法
- (void)animationDidStart:(CAAnimation *)anim
{
    
}

-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    //  開啟事務
    [CATransaction begin];
    
    // 關閉隱式動畫屬性
    [CATransaction setDisableActions:YES];
    
    _layer.position = [[anim valueForKey:@"LayerPosition"] CGPointValue];
    
    [CATransaction commit];
    
}



- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end