关键帧动画CAKeyframeAnimation

之所以叫做关键帧动画是因为,这个类可以实现,某一属性按照一串的数值进行动画,就好像制作动画的时候一帧一帧的制作一样。

一般使用的时候  首先通过 animationWithKeyPath 方法 创建一个CAKeyframeAnimation实例,

 

CAKeyframeAnimation 的一些比较重要的属性

1. path

这是一个 CGPathRef  对象,默认是空的,当我们创建好CAKeyframeAnimation的实例的时候,可以通过制定一个自己定义的path来让  某一个物体按照这个路径进行动画。这个值默认是nil  当其被设定的时候  values  这个属性就被覆盖 

2. values

一个数组,提供了一组关键帧的值,  当使用path的 时候 values的值自动被忽略。

下面是一个简单的例子  效果为动画的连续移动一个block到不同的位置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CGMutablePathRef path = CGPathCreateMutable();
     //将路径的起点定位到  (50  120) 
     CGPathMoveToPoint(path,NULL,50.0,120.0);
     //下面5行添加5条直线的路径到path中
     CGPathAddLineToPoint(path, NULL, 60, 130);
     CGPathAddLineToPoint(path, NULL, 70, 140);
     CGPathAddLineToPoint(path, NULL, 80, 150);
     CGPathAddLineToPoint(path, NULL, 90, 160);
     CGPathAddLineToPoint(path, NULL, 100, 170);
     //下面四行添加四条曲线路径到path
     CGPathAddCurveToPoint(path,NULL,50.0,275.0,150.0,275.0,70.0,120.0);
     CGPathAddCurveToPoint(path,NULL,150.0,275.0,250.0,275.0,90.0,120.0);
     CGPathAddCurveToPoint(path,NULL,250.0,275.0,350.0,275.0,110.0,120.0);
     CGPathAddCurveToPoint(path,NULL,350.0,275.0,450.0,275.0,130.0,120.0);
     //以“position”为关键字 创建 实例
     CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath: @"position" ];
     //设置path属性
     [animation setPath:path];
     [animation setDuration:3.0];
     //这句代码 表示 是否动画回到原位
    // [animation setAutoreverses:YES];
     CFRelease(path);
     [self.block.layer addAnimation:animation forKey:NULL];

 运行后  block会先沿着直线移动,之后再沿着设定的曲线移动,完全按照我们设定的“关键帧”移动。

下面一个例子是利用values制作的动画

?
1
2
3
4
5
6
7
8
9
10
11
CGPoint p1=CGPointMake(50, 120);
     CGPoint p2=CGPointMake(80, 170);
     CGPoint p3=CGPointMake(30, 100);
     CGPoint p4=CGPointMake(100, 190);
     CGPoint p5=CGPointMake(200, 10);
     NSArray *values=[NSArray arrayWithObjects:[NSValue valueWithCGPoint:p1],[NSValue valueWithCGPoint:p2],[NSValue valueWithCGPoint:p3],[NSValue valueWithCGPoint:p4],[NSValue valueWithCGPoint:p5], nil];
     CAKeyframeAnimation
     *animation = [CAKeyframeAnimation animationWithKeyPath: @"position" ]; [animation setValues:values];
     [animation setDuration:3.0];
     [animation setAutoreverses:YES];
     [self.block.layer addAnimation:animation forKey:NULL];

 也非常简单,到目前位置,只用到了CAKeyframeAnimation的两个关键属性就能完成动画,下面的一些属性提供了更加细致化,更加强大的功能。

 

设定每一帧的时间

默认情况下,一帧动画的播放,分割 的时间是动画的总时间除以帧数减去一。你可以通过下面的公式决定每帧动画的时间:总时间/(总帧数-1)。 例如,如果你指定了一个 5 帧,10 秒的动画,那么每帧的时间就是 2.5 秒钟:10/(5-1)=2.5。你可以做更多 的控制通过使用 keyTimes 关键字,你可以给每帧动画指定总时间之内的某个时间点。 

通过设置属性keyTimes,能实现这个功能,这个属性是一个数组,其成员必须是NSNumber。

同时 这个属性的设定值要与calculationMode属性相结合,同时他们有一定的规则,

The appropriate values in the keyTimes array are dependent on the calculationMode property.

  • If the calculationMode is set to kCAAnimationLinear, the first value in the array must be 0.0 and the last value must be 1.0. Values are interpolated between the specified key times.

  • If the calculationMode is set to kCAAnimationDiscrete, the first value in the array must be 0.0.

  • If the calculationMode is set to kCAAnimationPaced or kCAAnimationCubicPaced, the keyTimes array is ignored。

如果keyTimes的值不合法,或者不符合上面的规则,那么就会被忽略。

?
1
2
3
4
5
[animation setCalculationMode:kCAAnimationLinear]; [animation setKeyTimes:
[NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.25], [NSNumber numberWithFloat:0.50],
[NSNumber numberWithFloat:0.75], [NSNumber numberWithFloat:1.0], nil]];

 

calculationMode

这个属性用来设定 关键帧中间的值是怎么被计算的

可选的值有

NSString * const kCAAnimationLinear;
NSString * const kCAAnimationDiscrete;   只展示关键帧的状态,没有中间过程,没有动画。
NSString * const kCAAnimationPaced;
NSString * const kCAAnimationCubic;
NSString * const kCAAnimationCubicPaced;




关键帧动画的基础步骤

1.决定你想要做动画的属性(例如,框架,背景,锚点,位置,边框,等等) 2.在动画对象值的区域中,指定开始,结束,和中间的值。这些都是你的关键帧(看清单 4-2)
3.使用 duration 这个字段指定动画的时间
4.通常来讲,通过使用 times 这个字段,来给每帧动画指定一个时间。如果你没有指定这些,核心动画就

会通过你在 values 这个字段指定的值分割出时间段。
5.通常,指定时间功能来控制步调。 这些都是你需要做的。你创建你的动画和增加他们到层中。调用-addAnimation 就开始了动画。 

以一个画三角形的实例为例
(参考那本名字很长的core animation的书。。。)

Assumption:
1.实现以 imageView为画笔,用pink颜色自动动态画出一个三角形。
2.self.imageView是一个笔形状的图片,self.starPath是一个CGMutablePathRef类型的变量。
3.假设是点了某个按钮,动画开始播放的
比如:- (IBAction) buttonClicker :(id)sender {
                  [self createPath];    //给starPath初始化并设置起点
                  [self startAnimation];    //开始动画
            }

- (void) createPath {
   self.starPath = CGPathCreateMutable();    //alloc,需要在结束的时候调用CFRelease(_starPath);
    CGPathMoveToPoint(self.starPath, NULL, 40, 80);    //设置起点
}

- (void) startAnimation {
    if (self.starPath) {     //如果不存在就创建一次,如果存在了就清空重新创建
        CFRelease(self.starPath);
        [self createPath];
        [[self.view layer] setNeedsDisplay]; 
    }
    
    CGMutablePathRef path = CGPathCreateMutable();   //初始创建路线
    CGPathMoveToPoint(path, NULL, 40, 80);    //路线起点
    CGPathAddLineToPoint(path, NULL,80 , 150);    //连线到第二个点
    CGPathAddLineToPoint(path, NULL,100 , 90);    //连线到第三个点
    CGPathCloseSubpath(path);   //路线close起来,即让第三个点和第一个点自动连接
    
    CAKeyframeAnimation *theAnimation = [CAKeyframeAnimation animationWithKeyPath:@" position"];
      theAnimation.path = path;   //动画路线
      theAnimation.duration = 10;  //动画总时间
      CFRelease(path);
      [self.imageView.layer addAnimation:theAnimation forKey:@"position"]; //让动画的执行者开始执行动画
    
//以下需要注意的是,这三个nstimer是同时开始计时的,所以里面的时间要注意按逻辑分配  
    [NSTimer scheduledTimerWithTimeInterval:3
                                     target:self
                                   selector:@selector(legOne:)
                                   userInfo:nil
                                    repeats:NO];    //画第一条线
    [NSTimer scheduledTimerWithTimeInterval:6
                                     target:self
                                   selector:@selector(legTwo:)
                                   userInfo:nil
                                    repeats:NO];    //画第二条线
    [NSTimer scheduledTimerWithTimeInterval:10
                                     target:self
                                   selector:@selector(legThree:)
                                   userInfo:nil
                                    repeats:NO];   //画第三条线

    [[self.view layer] setNeedsDisplay];
}

- (void) legOne:(id)sender {
    CGPathAddLineToPoint(self.starPath, NULL, 80, 150);  
    [[self.view layer] setNeedsDisplay];
}

- (void) legTwo:(id)sender {
    CGPathAddLineToPoint(self.starPath, NULL, 100, 90);
    [[self.view layer] setNeedsDisplay];
}

- (void) legThree:(id)sender {
    CGPathCloseSubpath(self.starPath);
    [[self.view layer] setNeedsDisplay];
}

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {   
    if (layer == [self.view layer]) {    
//设置笔刷颜色  
        CGColorRef pink = CGColorCreateGenericRGB(1.0, 0.5, 0.5, 1.0);
        CGContextSetStrokeColorWithColor(ctx, pink);
        CFRelease(pink);        
//开始画线
        CGContextBeginPath(ctx);
        CGContextAddPath(ctx, self.starPath);       
        CGContextSetLineWidth(ctx, 5.0);
        CGContextStrokePath(ctx);
    }   
}

总结说明:
1.可以看到这个的实现分为两个部分:画笔的动画+画线的形成
2.每次调用 setNeedsDisplay都会自动去调用 drawRect方法,而这个方法又会去调用 最后一个方法,然后在这个方法里实现画线。
3.最后一个方法实际上是CALayerDelegate的一个方法,所以要想调用,需要在初始的方法中设置delegate才行

你可能感兴趣的:(关键帧动画CAKeyframeAnimation)