CAPropertyAnimation 用法

一:CAPropertyAnimation基本概念


CAPropertyAnimation提供了如下方法来创建属性动画。

    + (instancetype)animationWithKeyPath:(NSString *)path;该方法仅需要一个参数,该参数只是一个字符串的值,指定CALayer的动画属性名,该设置属性动画控制CALayer的哪个动画属性持续的改变。

    

   除此之外,CAPropertyAnimation还支持如下属性:

    keyPath:该属性值返回创建CAPropertyAnimation时指定的参数。

    additive:该属性指定该属性动画是否以当前动画效果为基础。

    cumulative:该属性指定动画是否为累加效果。

    valueFunction:该属性值是一个CAValueFunction对象,该对象负责对属性改变的插值计算,系统已经提供了默认的插值计算方式,因此一般无须指定该属性。

    

   如果要控制CALayer的位移动画,直接使用属性动画控制CALayerposition持续改变即可。如果要控制该CALayer的缩放,旋转,斜切等效果,则需要以下属性:

    affineTransform:该属性值指定一个(- (CGAffineTransform)affineTransform;CGAffineTransform对象(变换矩阵),该对象代表CALayer执行X,Y两个维度(也就是平面)上的旋转,缩放,位移,斜切,镜像等变换矩阵。

    transform:该属性值指定一个CATransform3D对象,该对象代表对CALayer执行X,Y,Z三个维度(三维空间)中的旋转,缩放,位移,斜切,镜像等变换矩阵。很明显如果只是对CALayer进行平面上的变换,指定普通的affineTransform属性即可,如果要对CALayer执行三维空间的变化,则需要指定transform属性。

   CATransform3D:就是下面的结构体

   struct CATransform3D

    {

        CGFloat m11, m12, m13, m14;

        CGFloat m21, m22, m23, m24;

        CGFloat m31, m32, m33, m34;

        CGFloat m41, m42, m43, m44;

    };

   其中(m11, m12, m13,m21, m22, m23,m31, m32, m33)将会组成变换矩阵,m14,m24,m34,m44只是占位符,通常m14,m24,m34会设置为0.m14设置为1.假如变换前的店坐标为(x,y,z),与该矩阵相乘后得到变换后该点的坐标。按矩阵相乘算法:

    [x,y,z].(m11,m12,m13

             m21,m22,m23=(x*m11+y*m21+z*m31 x*m12+y*m22+z*m32 x*m13+y*m23+z*m33

             m31,m32,m33)

   上面公司计算出来的坐标还要加上tx,ty,tz3X,Y,Z方向的偏移量。因此对于点(x,y,z)经过CATransform3D变换后,该点的实际坐标为(x*m11+y*m21+z*m31tx x*m12+y*m22+z*m32+ty x*m13+y*m23+z*m33+tz.

    

   一般来说可以使用 Core Animation提供的如下函数来创建三维变换矩阵。

    

    CATransform3DIsIdentity(CATransform3D t) :判断t矩阵是否为单位矩阵

    CATransform3DEqualToTransform(CATransform3D a, CATransform3D b) :判断两个变换矩阵是否相等

    CATransform3DMakeTranslation(CGFloat tx, CGFloat ty, CGFloat tz) :创建在x方向上移动tx,y方向上移动ty,z方向上移动tz的变换矩阵。

    CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz) :创建在x方向上缩放tx,y方向上缩放ty,z方向上缩放tz的变换矩阵。

    CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z) :创建基于指定旋转轴旋转angle弧度的变换,其中x,y,z用于确定旋转轴的方向。比如 (1,0,0)指定旋转轴为x轴,(1,1,0)指定以x,y轴夹角的中线为旋转轴。

    CATransform3DTranslate(CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz) :以已有t变换矩阵为基础进行位移变换。

    CATransform3DScale(CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz) :

   以已有t变换矩阵为基础进行缩放变换。

    CATransform3DRotate(CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z) :以已有t变换矩阵为基础进行旋转变换。

    CATransform3DConcat(CATransform3D a, CATransform3D b) :a变换矩阵进行累加

    CATransform3DInvert(CATransform3D t) :对已有的t变换矩阵执行反转。

    CATransform3DMakeAffineTransform(CGAffineTransform m) :CGAffineTransform矩阵包装成为CATransform3D变换矩阵,该CATransform3D也只有x,y维度变换。

    CATransform3DIsAffine(CATransform3D t) :如果t变换矩阵只有一个CGAffineTransform矩阵,则改函数返回YES.

    CATransform3DGetAffineTransform(CATransform3D t) :获取t变换矩阵所包含的CGAffineTransform变换矩阵。


二:CAPropertyAnimation的使用

   1:利用+ (instancetype)animationWithKeyPath:(NSString *)keyPath类方法创建属性动画

   2:如果使用基本属性动画CABasicAnimation,则可指定fromValue,toValue两个属性值,其中fromValue指定动画属性开始时的属性值,toValue指定动画属性结束的属性值.如果使用CAKeyframeAnimation属性动画,则指定values属性值,该属性值是一个 NSArray属性,其中第一个元素是属性的开始值.依次变化.区别在于CABasicAnimation只能够指定开始值和结束值.CAKeyframeAnimation则可以指定动画属性的多个值.CAKeyframeAnimation还可以通过控制路劲来控制移动.

   3:调用 CALayer- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key添加动画即可.key用于多图层进行分辨.单图层看不用设置.


三:demo 实现基本的位移 缩放 旋转 组合动画

#import <QuartzCore/QuartzCore.h>

#import "FKViewController.h"


@implementation FKViewController

CALayer *imageLayer;

- (void)viewDidLoad{

        [superviewDidLoad];

       //创建一个CALayer对象

       imageLayer = [CALayerlayer];

       //设置该CALayer的边框、大小、位置等属性

       imageLayer.cornerRadius =6;

       imageLayer.borderWidth =1;

       imageLayer.borderColor = [UIColor blackColor].CGColor;

       imageLayer.masksToBounds =YES;

       imageLayer.frame =CGRectMake(30,30,100, 135);

       //设置该imageLayer显示的图片

       imageLayer.contents = (id)[[UIImage imageNamed:@"android"]CGImage];

       [self.view.layer addSublayer:imageLayer];

    

       NSArray* bnTitleArray = [NSArray arrayWithObjects:@"位移",@"旋转" ,@"缩放" ,@"动画组" ,nil];

       //获取屏幕的内部高度

       CGFloat totalHeight = [UIScreen mainScreen].bounds.size.height;

       NSMutableArray* bnArray = [[NSMutableArray alloc]init];

       //采用循环创建4个按钮

       for(int i =0 ; i < 4 ; i++){

       UIButton* bn = [UIButton buttonWithType:UIButtonTypeRoundedRect];

       bn.frame =CGRectMake(5 + i *80, totalHeight - 45 - 20 , 70 ,35);

       [bnsetTitle:[bnTitleArrayobjectAtIndex:i] forState:UIControlStateNormal];

       [bnArray addObject:bn];

       [self.viewaddSubview:bn];

        }

 //4个按钮绑定不同的事件处理方法

[[bnArray objectAtIndex:0addTarget:self action:@selector(move:) forControlEvents:UIControlEventTouchUpInside];    [[bnArray objectAtIndex:1addTarget:self action:@selector(rotate:) forControlEvents:UIControlEventTouchUpInside];

[[bnArray objectAtIndex:2addTarget:self action:@selector(scale:) forControlEvents:UIControlEventTouchUpInside];

[[bnArray objectAtIndex:3addTarget:self action:@selector(group:) forControlEvents:UIControlEventTouchUpInside];

}


-(void) move:(id)sender

{

      CGPoint fromPoint =imageLayer.position;

      CGPoint toPoint =CGPointMake(fromPoint.x +80 , fromPoint.y);

      //创建不断改变CALayerposition属性的属性动画

      CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position"];

      //设置动画开始的属性值

      anim.fromValue = [NSValue valueWithCGPoint:fromPoint];

      //设置动画结束的属性值

      anim.toValue = [NSValue valueWithCGPoint:toPoint];

      anim.duration =0.5;

      imageLayer.position = toPoint;//设置移动后图片的位置。

      anim.removedOnCompletion =YES;

      //imageLayer添加动画

      [imageLayer addAnimation:animforKey:nil];

}


-(void) rotate:(id)sender

{

      //创建不断改变CALayertransform属性的属性动画

      CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform"];

      CATransform3D fromValue =imageLayer.transform;

      //设置动画开始的属性值

      anim.fromValue = [NSValue valueWithCATransform3D:fromValue];

      //X轴旋转180

      CATransform3D toValue =CATransform3DRotate(fromValue,M_PI , 1 , 0 , 0);

      //Y轴旋转180

      // CATransform3D toValue = CATransform3DRotate(fromValue, M_PI , 0 , 1 , 0);

      // // Z轴旋转180

      // CATransform3D toValue = CATransform3DRotate(fromValue, M_PI , 0 , 0 , 1);

      //设置动画结束的属性值

      anim.toValue = [NSValue valueWithCATransform3D:toValue];

      anim.duration =0.5;

      imageLayer.transform = toValue;

      anim.removedOnCompletion =YES;

      //imageLayer添加动画

      [imageLayer addAnimation:animforKey:nil];

}


-(void) scale:(id)sender

{

      //创建不断改变CALayertransform属性的属性动画

      CAKeyframeAnimation* anim = [CAKeyframeAnimation animationWithKeyPath:@"transform"];

      //设置CAKeyframeAnimation控制transform属性依次经过的属性值

      anim.values = [NSArrayarrayWithObjects:

      [NSValue valueWithCATransform3D:imageLayer.transform],

      [NSValue valueWithCATransform3D:CATransform3DScale(imageLayer.transform ,0.2,0.2,1)],

      [NSValue valueWithCATransform3D:CATransform3DScale(imageLayer.transform,2,2 ,1)],

      [NSValue valueWithCATransform3D:imageLayer.transform],nil];

      anim.duration =5;

      anim.removedOnCompletion =YES;

      //imageLayer添加动画

      [imageLayer addAnimation:animforKey:nil];

}


-(void) group:(id)sender

{

      CGPoint fromPoint =imageLayer.position;

      CGPoint toPoint =CGPointMake(280 , fromPoint.y +300);

      //创建不断改变CALayerposition属性的属性动画 

      CABasicAnimation* moveAnim = [CABasicAnimation animationWithKeyPath:@"position"];

      //设置动画开始的属性值

      moveAnim.fromValue = [NSValue valueWithCGPoint:fromPoint];

      //设置动画结束的属性值

      moveAnim.toValue = [NSValue valueWithCGPoint:toPoint];

      moveAnim.removedOnCompletion =YES;

      //创建不断改变CALayertransform属性的属性动画

      CABasicAnimation* transformAnim = [CABasicAnimation animationWithKeyPath:@"transform"];

      CATransform3D fromValue =imageLayer.transform;

      //设置动画开始的属性值

      transformAnim.fromValue = [NSValue valueWithCATransform3D: fromValue];

      //创建缩放为XY两个方向上缩放为0.5的变换矩阵

      CATransform3D scaleValue =CATransform3DScale(fromValue , 0.5 , 0.5,1);

       //Z轴旋转180度的变换矩阵

      CATransform3D rotateValue =CATransform3DRotate(fromValue,M_PI , 0 , 0 , 1);

      //计算两个变换矩阵的和

      CATransform3D toValue =CATransform3DConcat(scaleValue, rotateValue);

      //设置动画技术的属性值

      transformAnim.toValue = [NSValuevalueWithCATransform3D:toValue];

      //动画效果累加

      transformAnim.cumulative =YES;

      //动画重复执行2次,旋转360

      transformAnim.repeatCount =2;

      transformAnim.duration =3;

      //位移、缩放、旋转组合起来执行

      CAAnimationGroup *animGroup = [CAAnimationGroup animation];

      animGroup.animations = [NSArrayarrayWithObjects:moveAnim, transformAnim ,nil];

      animGroup.duration =6;

      //imageLayer添加动画

      [imageLayer addAnimation:animGroupforKey:nil];

}

@end


四:控制移动的路径

   对于CAKeyframeAnimation而言,它除了可通过values属性指定动画过程中的多个值之外,还可以通过path属性指定CALayer的移动路径,改属性就是CGPathRef,通过这种方式即可控制CALayer按我们指定的轨迹移动,从而执行更加细致的动画。


#import <QuartzCore/QuartzCore.h>

#import "FKViewController.h"


@interfaceFKViewController ()

@end


@implementation FKViewController

CALayer* fishLayer;

NSInteger fishFrame;

NSTimer* timer;

// 定义NSMutableArray装鱼的10个动画帧

NSMutableArray* fishFrameArray;


- (void)viewDidLoad

{

     [superviewDidLoad];

    

     //创建CALayer作为背景

     CALayer* bg = [CALayerlayer];

     //设置背景图片

     bg.contents = (id)[UIImageimageNamed:@"bg.jpg"].CGImage;

     bg.contentsGravity =kCAGravityCenter;

     bg.frame =CGRectMake(0,0,320, 480);

     [self.view.layer addSublayer:bg];

     fishFrameArray = [[NSMutableArray alloc]init];

     //初始化鱼的10个动画帧,并添加到fishFrameArray集合中

     for(int i =0 ; i < 10 ; i++){

     [fishFrameArray addObject:[UIImage imageNamed:[NSString stringWithFormat:@"fish%d.png" , i]]];//多张连串的图片

}

     //创建定时器控制小鱼的动画帧的改变。

     timer= [NSTimer scheduledTimerWithTimeInterval:0.15 

                     target:self 

                     selector:@selector(change) 

                     userInfo:nil 

                     repeats:YES];

     //创建CALayer

     fishLayer = [CALayer layer];

     //设置CALayer显示内容的对齐、缩放模式(不缩放,直接显示在中间)

     fishLayer.contentsGravity =kCAGravityCenter;

     //设置fishLayer的大小

     fishLayer.frame =CGRectMake(128,6,90, 40);

     [self.view.layeraddSublayer:fishLayer];

    

     //创建一个按钮,通过该按钮触发小鱼的游动

     UIButton* bn = [UIButton buttonWithType:UIButtonTypeRoundedRect];

     bn.frame =CGRectMake(10 ,10 , 60 ,35);

     [bnsetTitle:@"开始"forState:UIControlStateNormal];

     [self.viewaddSubview:bn];

     //用户点击按钮时,激发start:方法

     [bn addTarget:self action:@selector(start:) forControlEvents:UIControlEventTouchUpInside];

}


-(void) start:(id)sender

{

      //创建对CALayerposition属性执行控制的属性动画

      CAKeyframeAnimation* anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];

      //创建路径

      CGMutablePathRef movePath =CGPathCreateMutable();

      //添加一条圆形的路径

       CGPathAddArc(movePath,nil,170, 175, 150, -M_PI /2,M_PI * 3 / 2, YES);

      //设置anim动画的移动路径

       anim.path = movePath;

      //创建对CALayertransform属性执行控制的属性动画

      CAKeyframeAnimation* anim2 = [CAKeyframeAnimation animationWithKeyPath:@"transform"];

      //指定关键帧动画的3个关键值:分别是不旋转,旋转180度,旋转360

      anim2.values = [NSArray arrayWithObjects[NSValue valueWithCATransform3D:CATransform3DIdentity],

[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI , 0,0,1)],

[NSValue valueWithCATransform3D:CATransform3DMakeRotation(2 * M_PI ,0,0,1)],nil];

    

      //使用动画组来组合2个动画

      CAAnimationGroup *animGroup = [CAAnimationGroup animation];

      animGroup.animations = [NSArray arrayWithObjects:anim, anim2, nil];

      //指定动画重复10

      animGroup.repeatCount =10;

      animGroup.duration =24;

     //fishLayer添加动画

     [fishLayer addAnimation:animGroupforKey:@"move"];

}


// 该方法由定时器触发,不断更改fishLayer显示的动画帧

- (void) change

{

     fishLayer.contents = (id)[[fishFrameArray

      objectAtIndex:fishFrame++ %10]CGImage];

}

@end



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值