Core Animation 总结

以前由于项目需要 也写了一些动画 ,但是知识不系统,很散。这段时间趁着项目完成的空袭,来跟着大神的脚步系统的总结一下iOS中Core Animation的知识点。
原博客地址

本文主要从Core Animation的Layer角度来讲解动画,涵盖四个部分:

  • 1.基础动画 会讲到时间函数和一些关键的属性
  • 2.基于关键帧的动画 讲到沿着指定路径运行的动画
  • 3.动画组 多个动画组合到一起形成复杂的动画
  • 4.简单讲一讲有关动画的代理

Layer TreeLayer Tree

分为三种,Model Layer Tree,Presentation Tree,Render Tree其中,Render Tree为CoreAnimation私有的,是CoreAnimation具体实现使用的私有Tree,这里不做讨论。Model Layer Tree:存储的是模态对象,也是我们通常处理的对象,比如layer.position = CGPointMake(10.0,10.0)修改的就是Model Layer TreePresentation Tree:存储的是正在执行的动画的当前状态,是个动态的树,由这个树来获取当前动画运行到哪里。这两点对后续Core Animation的深入理解很重要。上述三种Tree的对应关系如下图


一 为什么要设计动画

动画提供了一个渐变的方式来表达变化,使用动画可以避免各种动画突变,造成用户困惑。
iOS中,使用CoreAnimation只要指定始末状态或者关键帧状态,CoreAnimation会高效的为我们创建补间动画。

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

这里我重复的介绍两种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,那么在动画执行完毕后,图层会保持显示动画执行后的状态。但在实质上,图层的属性值还是动画执行前的初始值,并没有真正被改变。

2.2CAKeyframeAnimation——关键帧动画

关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值CABasicAnimation可看做是只有2个关键帧的CAKeyframeAnimation
属性说明:


2.3 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 + 100);//该属性的结束值
    animation.duration = 1;//完成一次动画需要的时间
    //设置动画进行的方式
    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 = @(100);
    animation.duration = 1;//完成一次动画需要的时间
    //设置动画进行的方式
    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 + 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)设置让动画停在结束的位置

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.4 基于关键帧的动画

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

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.4 动画组

所谓,动画组就是把几个动画组合到一起,然后一起执行,通常复杂的动画都是由动画组来实现的。举个例子:沿着上个例子的路径运动,运动的同时透明度渐变。

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); 
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"];

2.5 动画的代理

通过设置代理可以监听动画开始和结束的事件通过设置delegate,来监听两个函数

animationDidStart:(CAAnimation *)anim
animationDidStop:(CAAnimation *)anim finished:(BOOL)flag

这里的flag判断动画是否执行完毕
附录:coreAnimation中的keyPath 属性


三.CAAnimation——简介

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



fillMode 属性设置
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。kCAFillModeBoth 这个其实就是上面两个的合成.动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态

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;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容