本文主要从CoreAnimation的Layer角度来讲解动画,我想从 CALayer的角度更好理解,后续还会有第二篇从UIKIt的UIView角度来讲解动画,第三篇讲解UIDynamicAnimation,第三篇我 会讲到UIViewController切换时候的动画。

本文主要涵盖四个部分

1.基础动画-会讲到时间函数和一些关键的属性

2.基于关键帧的动画-讲到沿着指定路径运行的动画

3.动画组-多个动画组合到一起形成复杂的动画

4.简单讲一下讲一下有关动画的代理

(一)为什么要设计动画?

动画提供了一个渐变的方式来表达变化,使用动画可以避免各种界面突变,造成用户困惑。

IOS中,使用CoreAnimation只要指定始末状态或者关键帧的状态,CoreAnimation会高效的为我们创建补间动画。


(二)从CALayer的角度来看的三种动画

首先不熟悉CALayer的同学看看前两篇的CALayer的内容,这是CoreAnimation的基础。这里我重复的介绍两种CALayer的Tree。

Presentation Tree-对应在动画的过程中,CALayer的属性

Model Tree-对应CALayer的实际属性。

通过使用 -[CALayer presentationLayer] 和 -[CALayer modelLayer]可以访问两种Tree

动画的过程实际上是修改Presentation Tree


2.1 基础的动画

第一个简单的动画,我希望imageview向右移动100的距离,移动方式easeInOut(加速开始,减速结束)。

效果如图:

              

代码如下,通常有两种方式来影响动画

 

  1. <pre name="code" class="objc">    CABasicAnimation * animation = [CABasicAnimation animation];  
  2.     animation.keyPath = @"position.x";//KVC的方式来访问属性  
  3.     animation.fromValue = @(self.imageview.layer.position.x);//该属性开始的值  
  4.     animation.toValue = @(self.imageview.layer.position.x + 100);//结束的值  
  5.     animation.duration = 1;//持续时间  
  6.     animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];//结束函数  
  7.     [self.imageview.layer addAnimation:animation forKey:@"basic"];//添加动画  


通过fromValue和toValue是一种方式,当然也可以通过byValue的方式,byValue在初值上加上byValue的变化,通过以下代码也可以实现上述动画

  1. CABasicAnimation * animation = [CABasicAnimation animation];  
  2.    animation.keyPath = @"position.x";  
  3.    animation.byValue = @(100);  
  4.    animation.duration = 1;  
  5.    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];  
  6.    [self.imageview.layer addAnimation:animation forKey:@"basic"];  

但是,结束后会发现,imageview又恢复到原处。这是因为在动画的过程中,我们修改的是Presentation Tree,并没有实际修改CALayer的属性。想要让动画停在结束的位置,通常有两种方式,

(1)修改属性

代码如下

 

  1. CABasicAnimation * animation = [CABasicAnimation animation];  
  2.   animation.keyPath = @"position.x";  
  3.   animation.fromValue = @(self.imageview.layer.position.x);  
  4.   animation.toValue = @(self.imageview.layer.position.x + 100);  
  5.   animation.duration = 1;  
  6.   animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];  
  7.   [self.imageview.layer addAnimation:animation forKey:@"basic"];  
  8.   self.imageview.layer.position = CGPointMake(self.imageview.layer.position.x+100, self.imageview.layer.position.y);  


(2)设置让动画停在结束的位置"code" class="objc">  CABasicAnimation * animation = [CABasicAnimation animation];  

  •     animation.keyPath = @"position.x";  
  •     animation.fromValue = @(self.imageview.layer.position.x);  
  •     animation.toValue = @(self.imageview.layer.position.x + 100);  
  •     animation.duration = 1;  
  •     animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];  
  •     animation.removedOnCompletion = NO;//动画结束了禁止删除  
  •     animation.fillMode = kCAFillModeForwards;//停在动画结束处  
  •     [self.imageview.layer addAnimation:animation forKey:@"basic"];  

一般采用前者,因为动画往往的结束是实际的属性的改变。

这里再讲解下时间函数

时间函数决定了动画如何执行,时间函数决定了动画的数学模型,比如速度速度最好不要有突变, 系统提供的时间函数有以下几种

NSString *constkCAMediaTimingFunctionLinear;线性

NSString *constkCAMediaTimingFunctionEaseIn;加速进入

NSString *constkCAMediaTimingFunctionEaseOut;减速停止

NSString*constkCAMediaTimingFunctionEaseInEaseOut;加速进入减速停止,这个是常用的

NSString *constkCAMediaTimingFunctionDefault;默认

当然,时间函数支持自定义,用如下函数

functionWithControlPoints::::

这个函数的4个点决定了一个三维的贝塞尔曲线来决定时间函数。这里不深入讲解了。

最后,这一点尤为重要,就是在传递CAAnimation的对象或者子类给Layer的时候,传递的是copy

2.2 基于关键帧的动画

以下是一个基于关键帧创建的抖动的动画,采用在时间点对应的位置来创建动画

 

  1. CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];  
  2.   animation.keyPath = @"position.x";  
  3.   NSInteger initalPositionX = self.imageview.layer.position.x;  
  4.   animation.values = @[@(initalPositionX),  
  5.                        @(initalPositionX + 10),  
  6.                        @(initalPositionX - 10),  
  7.                        @(initalPositionX + 10),  
  8.                        @(initalPositionX)];  
  9.   animation.keyTimes = @[  
  10.                          @(0),  
  11.                          @(1/6.0),  
  12.                          @(3/6.0),  
  13.                          @(5/6.0),  
  14.                          @(1)];  
  15.   [self.imageview.layer addAnimation:animation forKey:@"keyFrame"];  

当然,基于关键帧的动画支持沿着路径运动,可以设置时间函数来决定运动的方式

例如以下创建一个比较复杂的运动,首先移动到(200,200),然后沿着以该点为圆心,逆时针旋转半圈,最后停在结束的位置。

动画的过程中,imageview沿着路径转动

 

 

  1. CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];  
  2. animation.keyPath = @"position";  
  3. //Create Path  
  4. CGMutablePathRef mutablepath = CGPathCreateMutable();  
  5. CGPathMoveToPoint(mutablepath, nil,self.imageview.layer.position.x, self.imageview.layer.position.y);  
  6. CGPathAddLineToPoint(mutablepath,nil,200,200);  
  7. CGPathAddArc(mutablepath, nil,200,200,100,0,M_PI,YES);  
  8. //set path  
  9. animation.path = mutablepath;  
  10. animation.duration = 4.0;  
  11. animation.rotationMode = kCAAnimationRotateAuto;  
  12. animation.removedOnCompletion = NO;//动画结束了禁止删除  
  13. animation.fillMode = kCAFillModeForwards;//停在动画结束处  
  14. [self.imageview.layer addAnimation:animation forKey:@"PathAnimation"];  

2.3 动画组

所谓,动画组就是把几个动画组合到一起,然后一起执行,通常复杂的动画都是由动画组来实现的。

举个例子:沿着上个例子的路径运动,运动的同时透明度渐变。

    1. CAKeyframeAnimation * pathAnimation = [CAKeyframeAnimation animation];  
    2.   pathAnimation.keyPath = @"position";  
    3.   //Create Path  
    4.   CGMutablePathRef mutablepath = CGPathCreateMutable();  
    5.   CGPathMoveToPoint(mutablepath, nil,self.imageview.layer.position.x, self.imageview.layer.position.y);  
    6.   CGPathAddLineToPoint(mutablepath,nil,200,200);  
    7.   CGPathAddArc(mutablepath, nil,200,200,100,0,M_PI,YES);  
    8.   //set path  
    9.   pathAnimation.path = mutablepath;  
    10.   pathAnimation.rotationMode = kCAAnimationRotateAuto;  
    11.   [self.imageview.layer addAnimation:pathAnimation forKey:@"PathAnimation"];  
    12.     
    13.   //透明度变化  
    14.   CAKeyframeAnimation * opacityAnimation = [CAKeyframeAnimation animation];  
    15.   opacityAnimation.keyPath = @"opacity";  
    16.   opacityAnimation.values = @[@(1.0),  
    17.                        @(0.5),  
    18.                        @(0.0),  
    19.                        @(0.5),  
    20.                        @(1.0)];  
    21.   opacityAnimation.calculationMode = kCAAnimationPaced;  
    22.   [self.imageview.layer addAnimation:opacityAnimation forKey:@"OpacityAnination"];  
    23.   //配置动画组  
    24.   CAAnimationGroup * animationGroup = [[CAAnimationGroup alloc] init];  
    25.   animationGroup.animations = @[pathAnimation,opacityAnimation];  
    26.   animationGroup.duration = 4.0;  
    27.   animationGroup.removedOnCompletion = NO;  
    28.   animationGroup.fillMode = kCAFillModeBackwards;  
    29.   [self.imageview.layer addAnimation:animationGroup forKey:@"GroupAnimation"]; 
posted on 2015-01-25 18:31  移动开发者  阅读(604)  评论(0编辑  收藏  举报