iOS CoreAnimation详解(一) 有关Layer的动画
以前由于项目需要 也写了一些动画 ,但是知识不系统,很散。这段时间趁着项目完成的空袭,来跟着大神的脚步系统的总结一下iOS中Core Animation的知识点。
原博客地址: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 基础的动画 CABasicAnimation
属性说明

动画过程说明
随着动画的进行,在长度为duration的持续时间内,keyPath相应属性的值从fromValue渐渐地变为toValue。
keyPath内容是CALayer的可动画Animatable属性。
如果fillMode = kCAFillModeForwards同时removedOnComletion = NO,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。
CAKeyframeAnimation——关键帧动画
关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:
CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值
CABasicAnimation可看做是只有2个关键帧的CAKeyframeAnimation
属性说明:

CAAnimationGroup——动画组
动画组,是CAAnimation的子类,可以保存一组动画对象,将CAAnimationGroup对象加入层后,组中所有动画对象可以同时并发运行。
默认情况下,一组动画对象是同时运行的,也可以通过设置动画对象的beginTime属性来更改动画的开始时间。
属性说明:

第一个简单的动画,我希望imageview向右移动100的距离,移动方式easeInOut(加速开始,减速结束)。
代码如下,通常有两种方式来影响动画
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = @"position.x";//KVC的方式来访问属性
animation.fromValue = @(self.imageView.layer.position.x);//该属性开始的值
animation.toValue = @(self.imageView.layer.position.x + );//该属性的结束值
animation.duration = ;//完成一次动画需要的时间
//设置动画进行的方式
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[self.imageView.layer addAnimation:animation forKey:@"basic"];
通过fromValue和toValue是一种方式,当然也可以通过byValue的方式,byValue在初值上加上byValue的变化,通过以下代码也可以实现上述动画
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.byValue = @();
animation.duration = ;//完成一次动画需要的时间
//设置动画进行的方式
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[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 + );
animation.duration = ;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.imageview.layer addAnimation:animation forKey:@"basic"];
self.imageview.layer.position = CGPointMake(self.imageview.layer.position.x+, self.imageview.layer.position.y);
(2)设置让动画停在结束的位置
CABasicAnimation * animation = [CABasicAnimation animation];
animation.keyPath = @"position.x";
animation.fromValue = @(self.imageview.layer.position.x);
animation.toValue = @(self.imageview.layer.position.x + );
animation.duration = ;
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 + ),
@(initalPositionX - ),
@(initalPositionX + ),
@(initalPositionX)];
animation.keyTimes = @[
@(),
@(/6.0),
@(/6.0),
@(/6.0),
@()];
[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,,);
CGPathAddArc(mutablepath, nil,,,,,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,,);
CGPathAddArc(mutablepath, nil,,,,,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判断动画是否执行完毕
4.付coreAnimation中的keyPath 属性

CAAnimation——简介
是所有动画对象的父类,负责控制动画的持续时间和速度,是个抽象类,不能直接使用,应该使用它具体的子类。
基本属性说明

fillMode 属性设置
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。
kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态
CALayer上动画的暂停和恢复
#pragma mark 暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; // 让CALayer的时间停止走动
layer.speed = 0.0;
// 让CALayer的时间停留在pausedTime这个时刻
layer.timeOffset = pausedTime;
} #pragma mark 恢复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
// 1. 让CALayer的时间继续行走
layer.speed = 1.0;
// 2. 取消上次记录的停留时刻
layer.timeOffset = 0.0;
// 3. 取消上次设置的时间
layer.beginTime = 0.0;
// 4. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
// 5. 设置相对于父坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
iOS CoreAnimation详解(一) 有关Layer的动画的更多相关文章
- IOS SDK详解
来源:http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html?page=1#42803301 博客专栏>移动开发专栏>I ...
- 【转】IOS AutoLayout详解(三)用代码实现(附Demo下载)
转载自:blog.csdn.net/hello_hwc IOS SDK详解 前言: 在开发的过程中,有时候创建View没办法通过Storyboard来进行,又需要AutoLayout,这时候用代码创建 ...
- iOS路由详解
本文如题,路由详解,注定是一篇详细解释iOS路由原理及使用的文章,由于此时正在外地出差,无法详细一一写出,只能不定时的补充. 一.什么是iOS路由 路由一词来源于路由器,可以实现层级之间消息转发的功能 ...
- IOS 手势详解
在IOS中手势可以让用户有很好的体验,因此我们有必要去了解一下手势. (在设置手势是有很多值得注意的地方) *是需要设置为Yes的点击无法响应* *要把手势添加到所需点击的View,否则无法响应* 手 ...
- IOS SizeClasses 详解
SizeClasses 详解 iOS 8在应用界面的可视化设计上添加了一个新的特性-Size Classes.对于任何设备来说,界面的宽度和高度都只分为三种描述:紧凑,任意和宽松.这样开发者便可以无视 ...
- iOS模式详解—「runtime面试、工作」看我就 🐒 了 ^_^.
Write in the first[写在最前] 对于从事 iOS 开发人员来说,当提到 ** runtime时,我想都可以说出来 「runtime 运行时」和基本使用的方法.相信很多开发者跟我当初一 ...
- iOS 模式详解—「runtime面试、工作」看我就 🐒 了 ^_^.
引导 Copyright © PBwaterln Unauthorized shall not be *copy reprinted* . 对于从事 iOS 开发人员来说,所有的人都会答出「runti ...
- ios学习--详解IPhone动画效果类型及实现方法
详解IPhone动画效果类型及实现方法是本文要介绍的内容,主要介绍了iphone中动画的实现方法,不多说,我们一起来看内容. 实现iphone漂亮的动画效果主要有两种方法,一种是UIView层面的,一 ...
- iOS UIControl 详解
UIControl是UIView的子类,当然也是UIResponder的子类.UIControl是诸如UIButton,UISwitch,UItextField等控件的父类,它本身包含了一些属性和方法 ...
随机推荐
- 4. ValueStack 和 OGNL
1. 属性哪来的 当我们通过Action处理完用户请求以后,可以直接在页面中获取到 action 的属性值. 如果我们在页面中尝试遍历四个域中的属性,会发现域中并没有username之类的Action ...
- 如何在Zabbix上安装MySQL监控插件PMP
PMP,全称是Percona Monitoring Plugins,是Percona公司为MySQL监控写的插件.支持Nagios,Cacti.从PMP 1.1开始,支持Zabbix. 下面,看看如何 ...
- LinqToDB 源码分析——轻谈Linq查询
LinqToDB框架最大的优势应该是实现了对Linq的支持.如果少了这一个功能相信他在使用上的快感会少了一个层次.本来笔者想要直接讲解LinqToDB框架是如何实现对Linq的支持.写到一半的时候却发 ...
- 从零自学Hadoop(20):HBase数据模型相关操作上
阅读目录 序 介绍 命名空间 表 系列索引 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 序 ...
- Keil> 编译器特有的功能 > 关键字和运算符 > __weak
__weak 此关键字指示编译器弱导出符号. 可以将 __weak 关键字应用于函数和变量声明以及函数定义. 用法 函数和变量声明 对于声明,此存储类指定一个 extern 对象声明,即使不存在,也不 ...
- 《高性能javascript》 领悟随笔之-------DOM编程篇(二)
<高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...
- Node学习笔记(一):stream流操作
NodeJs中谈及较多的可能就是Stream模块了,先写一个简单的ajax回调 $.post("index.php",{data:'aaa',order:'ccc'},functi ...
- .NET文件并发与RabbitMQ(初探RabbitMQ)
本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...
- MongoDB 存储引擎和数据模型设计
标签: MongoDB NoSQL MongoDB 存储引擎和数据模型设计 1. 存储引擎 1.1 存储引擎是什么 1.2 MongoDB中的默认存储引擎 2. 数据模型设计 2.1 内嵌和引用 2. ...
- 浅谈JDBC访问MySQL数据库
经过我自己的总结后,其实很简单,只需要记住四个步骤,JDBC这部分的学习就可以掌握差不多了,请多多指教. 加载注册JDBC驱动: 打开数据库: 创建向数据库发送sql语句的statement: Res ...