以前由于项目需要 也写了一些动画 ,但是知识不系统,很散。这段时间趁着项目完成的空袭,来跟着大神的脚步系统的总结一下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的动画的更多相关文章

  1. IOS SDK详解

    来源:http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html?page=1#42803301 博客专栏>移动开发专栏>I ...

  2. 【转】IOS AutoLayout详解(三)用代码实现(附Demo下载)

    转载自:blog.csdn.net/hello_hwc IOS SDK详解 前言: 在开发的过程中,有时候创建View没办法通过Storyboard来进行,又需要AutoLayout,这时候用代码创建 ...

  3. iOS路由详解

    本文如题,路由详解,注定是一篇详细解释iOS路由原理及使用的文章,由于此时正在外地出差,无法详细一一写出,只能不定时的补充. 一.什么是iOS路由 路由一词来源于路由器,可以实现层级之间消息转发的功能 ...

  4. IOS 手势详解

    在IOS中手势可以让用户有很好的体验,因此我们有必要去了解一下手势. (在设置手势是有很多值得注意的地方) *是需要设置为Yes的点击无法响应* *要把手势添加到所需点击的View,否则无法响应* 手 ...

  5. IOS SizeClasses 详解

    SizeClasses 详解 iOS 8在应用界面的可视化设计上添加了一个新的特性-Size Classes.对于任何设备来说,界面的宽度和高度都只分为三种描述:紧凑,任意和宽松.这样开发者便可以无视 ...

  6. iOS模式详解—「runtime面试、工作」看我就 🐒 了 ^_^.

    Write in the first[写在最前] 对于从事 iOS 开发人员来说,当提到 ** runtime时,我想都可以说出来 「runtime 运行时」和基本使用的方法.相信很多开发者跟我当初一 ...

  7. iOS 模式详解—「runtime面试、工作」看我就 🐒 了 ^_^.

    引导 Copyright © PBwaterln Unauthorized shall not be *copy reprinted* . 对于从事 iOS 开发人员来说,所有的人都会答出「runti ...

  8. ios学习--详解IPhone动画效果类型及实现方法

    详解IPhone动画效果类型及实现方法是本文要介绍的内容,主要介绍了iphone中动画的实现方法,不多说,我们一起来看内容. 实现iphone漂亮的动画效果主要有两种方法,一种是UIView层面的,一 ...

  9. iOS UIControl 详解

    UIControl是UIView的子类,当然也是UIResponder的子类.UIControl是诸如UIButton,UISwitch,UItextField等控件的父类,它本身包含了一些属性和方法 ...

随机推荐

  1. angular2系列教程(三)components

    今天,我们要讲的是angualr2的components. 例子

  2. SharePoint 2013 Create taxonomy field

    创建taxonomy field之前我们首先来学习一下如果创建termSet,原因是我们所创建的taxonomy field需要关联到termSet. 简单介绍一下Taxonomy Term Stor ...

  3. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 特殊问题和实战经验(五)

    RAC 特殊问题和实战经验(五) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

  4. Vertica 6.1不完全恢复启动到LGE方法

    环境:RHEL6.2 + Vertica 6.1.3-7 确定所有节点的vertica进程都停掉(包括agent和python),如果有运行的,停止它或者杀掉它. 确定所有节点的spread进程都正常 ...

  5. 读书笔记--SQL必知必会14--组合查询

    14.1 组合查询 复合查询(compound query)或并(union),SQL允许执行多个查询(多条SELECT语句),并将结果作为一个查询结果集返回. 应用场景: 在一个查询中从不同的表返回 ...

  6. ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序

    原文:Developing ASP.NET Core applications using dotnet watch 作者:Victor Hurdugaci 翻译:谢炀(Kiler) 校对:刘怡(Al ...

  7. 在Azure上的VM镜像库中找到想要的镜像

    Azure上的虚机镜像库中, 有很多的镜像,其中当然也包括了用户自定义上传的镜像. 在Powershell中如果想使用这些镜像的话, 则需要知道其名称 下面这条命令,可以获得所有的镜像信息 $imag ...

  8. android权限

    一.WebView 访问internet 的权限: 1.在layout中增加一个WebView 控件: <WebView android:layout_width="match_par ...

  9. HTML课上小结

    HTML翻译为超文本标记语言<标签名>内容</标签名>静态网页动态网页的区别是看是否从数据中提取数据一般网页由几部分组分组成<html>开始标签 <head& ...

  10. 【Java每日一题】20161230

    // 20161229问题解析请点击今日问题下方的"[Java每日一题]20161230"查看(问题解析在公众号首发,公众号ID:weknow619)package Dec2016 ...