原创Blog,转载请注明出处
我的IOS SDK详解专栏,地址
http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html
本文主要从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(加速开始,减速结束)。
效果如图:
代码如下,通常有两种方式来影响动画
<pre name="code" class="objc"> CABasicAnimation * animation = [CABasicAnimation animation]; animation.keyPath = @"position.x";//KVC的方式来访问属性 animation.fromValue = @(self.imageview.layer.position.x);//该属性开始的值 animation.toValue = @(self.imageview.layer.position.x + 100);//结束的值 animation.duration = 1;//持续时间 animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];//结束函数 [self.imageview.layer addAnimation:animation forKey:@"basic"];//添加动画
CABasicAnimation * animation = [CABasicAnimation animation]; animation.keyPath = @"position.x"; animation.byValue = @(100); animation.duration = 1; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [self.imageview.layer addAnimation:animation forKey:@"basic"];
但是,结束后会发现,imageview又恢复到原处。这是因为在动画的过程中,我们修改的是Presentation Tree,并没有实际修改CALayer的属性。想要让动画停在结束的位置,通常有两种方式,
(1)修改属性
代码如下
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]; [self.imageview.layer addAnimation:animation forKey:@"basic"]; self.imageview.layer.position = CGPointMake(self.imageview.layer.position.x+100, self.imageview.layer.position.y);
(2)设置让动画停在结束的位置
<pre name="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 基于关键帧的动画
以下是一个基于关键帧创建的抖动的动画,采用在时间点对应的位置来创建动画
CAKeyframeAnimation * animation = [CAKeyframeAnimation animation]; animation.keyPath = @"position.x"; NSInteger initalPositionX = self.imageview.layer.position.x; animation.values = @[@(initalPositionX), @(initalPositionX + 10), @(initalPositionX - 10), @(initalPositionX + 10), @(initalPositionX)]; animation.keyTimes = @[ @(0), @(1/6.0), @(3/6.0), @(5/6.0), @(1)]; [self.imageview.layer addAnimation:animation forKey:@"keyFrame"];
当然,基于关键帧的动画支持沿着路径运动,可以设置时间函数来决定运动的方式
例如以下创建一个比较复杂的运动,首先移动到(200,200),然后沿着以该点为圆心,逆时针旋转半圈,最后停在结束的位置。
动画的过程中,imageview沿着路径转动
CAKeyframeAnimation * animation = [CAKeyframeAnimation animation]; animation.keyPath = @"position"; //Create Path CGMutablePathRef mutablepath = CGPathCreateMutable(); CGPathMoveToPoint(mutablepath, nil,self.imageview.layer.position.x, self.imageview.layer.position.y); CGPathAddLineToPoint(mutablepath,nil,200,200); CGPathAddArc(mutablepath, nil,200,200,100,0,M_PI,YES); //set path animation.path = mutablepath; animation.duration = 4.0; animation.rotationMode = kCAAnimationRotateAuto; animation.removedOnCompletion = NO;//动画结束了禁止删除 animation.fillMode = kCAFillModeForwards;//停在动画结束处 [self.imageview.layer addAnimation:animation forKey:@"PathAnimation"];这个动画的几幅关键截图
2.3 动画组
所谓,动画组就是把几个动画组合到一起,然后一起执行,通常复杂的动画都是由动画组来实现的。
举个例子:沿着上个例子的路径运动,运动的同时透明度渐变。
CAKeyframeAnimation * pathAnimation = [CAKeyframeAnimation animation]; pathAnimation.keyPath = @"position"; //Create Path CGMutablePathRef mutablepath = CGPathCreateMutable(); CGPathMoveToPoint(mutablepath, nil,self.imageview.layer.position.x, self.imageview.layer.position.y); CGPathAddLineToPoint(mutablepath,nil,200,200); CGPathAddArc(mutablepath, nil,200,200,100,0,M_PI,YES); //set path pathAnimation.path = mutablepath; pathAnimation.rotationMode = kCAAnimationRotateAuto; [self.imageview.layer addAnimation:pathAnimation forKey:@"PathAnimation"]; //透明度变化 CAKeyframeAnimation * opacityAnimation = [CAKeyframeAnimation animation]; opacityAnimation.keyPath = @"opacity"; opacityAnimation.values = @[@(1.0), @(0.5), @(0.0), @(0.5), @(1.0)]; opacityAnimation.calculationMode = kCAAnimationPaced; [self.imageview.layer addAnimation:opacityAnimation forKey:@"OpacityAnination"]; //配置动画组 CAAnimationGroup * animationGroup = [[CAAnimationGroup alloc] init]; animationGroup.animations = @[pathAnimation,opacityAnimation]; animationGroup.duration = 4.0; animationGroup.removedOnCompletion = NO; animationGroup.fillMode = kCAFillModeBackwards; [self.imageview.layer addAnimation:animationGroup forKey:@"GroupAnimation"];效果的几幅截图如图
(三)动画的代理
通过设置代理可以监听动画开始和结束的事件
通过设置delegate,来监听两个函数
animationDidStart:(CAAnimation *)anim
animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
这里的flag判断动画是否执行完毕
最后,附上wiki上设计动画的12个基本原则
https://en.wikipedia.org/wiki/12_basic_principles_of_animation
BTY:有没有同学知道CSDN怎么插入gif图片?
原文地址:http://blog.csdn.net/hello_hwc/article/details/43112379