核心动画 - Core Animation

  • 我所知道的Core Animation
    1. Core Animation负责所有的滚动、旋转、缩小和放大以及所有的iOS动画效果。其中UIKit类通常都有animated:参数部分,它可以允许是否使用动画。
    2. Core Animation的动画执行过程都是在后台操作的,不会阻塞主线程。不阻塞主线程,可以理解为在执行动画的时候还能点击(按钮)。用图形处理硬件操纵位图要比图形处理软件能获得更好的动画效果。因为操纵的是静态的位图,基于图层的绘图和基于视图的绘图在技术上有明显的不同。对基于视图的绘图,对视图的改变经常会触发调用视图的drawRect:方法以重绘视图内容。但是此种方式的代价相对较高,因为它是CPU在主线程上的操作。Core Animation通过尽可能的使用图形硬件操纵缓存后的位图来避免了这种开销,从而完成相同或相似的效果。
    3. Core Animation还与Quartz紧密结合在一起,每个UIView都关联到一个CALayer对象,CALayer是Core Animation中的图层。要注意的是,Core Animation是直接作用在CALayer上的,并非UIView。


      图1-iOS图形层关系
  • 核心动画类有一下分类:
    ①提供显示内容的图层类:CALayer
    ②动画和计时类:Animation and Timing Classes
    ③布局和约束类:CAConstraint
    ④事物类,在原子更新的时候组合图层类。核心动画的基础类包含在 Quartz核心框架(Quartz Core framework)里面,虽然它的其他图层类在其他图层类在其他框架里面定义。(CATransaction)

  • CAlayer层的属性
    (1)、position和anchorPoint
    CALayer有2个非常重要的属性:position和anchorPoint


    图2 -AnchorPoint
@property CGPoint position;

用来设置CALayer在父层中的位置,以父层的左上角为原点(0, 0)

@property CGPoint anchorPoint;

称为“定位点”、“锚点”决定着CALayer身上的哪个点会在position属性所指的位置,以自己的左上角为原点(0, 0),它的x、y取值范围都是0~1,默认值为(0.5, 0.5)
(2)、隐式动画
每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)所有的非Root Layer,也就是手动创建的CALayer对象,都存在着隐式动画
什么是隐式动画?

当对非Root Layer的部分属性进行修改时,默认会自动产生一些动画效果
而这些属性称为Animatable Properties(可动画属性)
列举几个常见的Animatable Properties:
bounds:用于设置CALayer的宽度和高度。修改这个属性会产生缩放动画
backgroundColor:用于设置CALayer的背景色。修改这个属性会产生背景色的渐变动画
position:用于设置CALayer的位置。修改这个属性会产生平移动画


  • CAAnimation (动画类)
    CAAnimation是所有动画类的父类,但是它不能直接使用,应该使用它的子类。


    图3-CAAnimation类的继承结构图

    常见属性有:

duration:动画的持续时间
repeatCount:动画的重复次数
repeatDuration:动画的重复时间
timingFunction:控制动画运行的节奏
fillMode:决定当前对象在非active时间段的行为.比如动画开始之前,动画结束之后
beginTime:可以用来设置动画延迟执行时间,若想延迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当前时间

类的说明:
(1)能用的动画类只有4个子类:CABasicAnimation、CAKeyframeAnimation、CATransition、CAAnimationGroup

①CABasicAnimation
通过设定起始点,终点,时间,动画会沿着你这设定点进行移动。可以看做特殊的CAKeyFrameAnimation
②CAKeyframeAnimation
Keyframe顾名思义就是关键点的frame,你可以通过设定CALayer的始点、中间关键点、终点的frame,时间,动画会沿你设定的轨迹进行移动
③CAAnimationGroup
Group也就是组合的意思,就是把对这个Layer的所有动画都组合起来。PS:一个layer设定了很多动画,他们都会同时执行,如何按顺序执行我到时候再讲。
④CATransition
这个就是苹果帮开发者封装好的一些动画

(2)CAMediaTiming是一个协议(protocol)。

CAPropertyAnimation是CAAnimation的子类,但是不能直接使用,要想创建动画对象,应该使用它的两个子类:CABasicAnimation和CAKeyframeAnimation。
它有个NSString类型的keyPath属性,你可以指定CALayer的某个属性名为keyPath,并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@"position"为keyPath,就会修改CALayer的position属性的值,以达到平移的动画效果


  • Core Animation的使用步骤
    1.使用它需要先添加QuartzCore.framework框架和引入主头文件<QuartzCore/QuartzCore.h>(iOS7不需要)
    2.初始化一个CAAnimation对象,并设置一些动画相关属性
    3.通过调用CALayer的addAnimation:forKey:方法增加CAAnimation对象到CALayer中,这样就能开始执行动画了
    4.通过调用CALayer的removeAnimationForKey:方法可以停止CALayer中的动画


    图4-基于图层的动画

补充一下animationWithKeyPath值的总结:


animationWithKeyPath值的总结.png
  • OC中的动画效果
    视图动画、帧动画
  • 三个问题
    1.什么事图层CALayer?
    核心动画的所有效果都是基于图层的,没有图层也就没有核心动画效果
    2.视图什么时候能够显示在屏幕上?
    1)调用drawRect方法,如果我们自己绘制了东西,他会显示出来
    2)在显示图形之前他会创建一个图层对象(CALayer),然后把需要的东西都放在图层上,然后呈现给用户看
    3)没有图层就没有视图的显示功能,也就是没有界面
    3.图层能够用来做什么?
    1)阴影效果
    2)边框效果
    3)圆角效果
    4)更强大的动画效果

本篇核心动画有以下几点内容:

1.核心动画基础知识
2.有关锚点
3.隐式动画
4.自定义图层
5.CAAnimation


其中CAAnimation又有以下几点小内容:

1.位移
2.缩放
3.透明度
4.旋转
5.组合动画
6.绕矩形环跑

示例

//实例1:(位移)以position作为参考点来执行动画的
-(void)WeiYi{
//创建基础动画
CABasicAnimation *ban = [CABasicAnimation animation];
//设置动画路径
//从什么值开始,因为fromValue是个id类型,所以把起点point包装成NSValue传递给他
//锚点的位置(如果不写fromValue,代表从当前位置开始变)
ban.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
//变化到什么值结束
ban.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 500)];

//设置动画对象
//keyPath 决定了执行怎样的动画
//使用kvc的方式来告诉动画,要使用layer的哪个属性变动来完成动画效果
//    NSString *keyPath = @"position";
//
//    [self.layer addAnimation:ban forKey:keyPath];

//没起作用,因为是在动画添加到layer之后的属性,所以没有起作用
ban.duration = 3.0;

//当动画执行完成后,还会回到最初的位置,这是核心动画的特点
//禁止归位,执行完动画之后移除动画效果
//注意这量两个属性,要改变核心动画的属性,必须都添加到layer之前,否则无效

//动画完成后不删除
ban.removedOnCompletion = NO;
//保持最新的状态
ban.fillMode = kCAFillModeForwards;
NSString *keyPath = @"position";
[self.layer addAnimation:ban forKey:keyPath];
}

//实例2:缩放属性
-(void)SuoFang{
CABasicAnimation *ban = [CABasicAnimation animation];
ban.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1)];
ban.duration = 1.0;

//  self.layer.transform =
//  transform.scale表示等比例拉伸
//  transform按照参数比例拉伸
ban.keyPath = @"transform";
//执行完动画不删除动画
ban.removedOnCompletion = NO;
//保持最新状态
ban.fillMode = kCAFillModeForwards;
//如果通过keyPath设置了属性,后面的参数可以传nil
[self.layer addAnimation:ban forKey:nil];
}

//实例3:透明度属性
- (void)TouMingDu{
    //初始化的时候就定制好动画类型
    CABasicAnimation *ban = [CABasicAnimation animationWithKeyPath:@"opacity"];
    //透明度是float类型
    ban.fromValue = [NSNumber numberWithFloat:1.0];
    ban.toValue = [NSNumber numberWithFloat:0.1];
    ban.duration = 3.0;
    ban.removedOnCompletion = NO;
    ban.fillMode = kCAFillModeForwards;
    [self.layer addAnimation:ban forKey:nil];
}

//实例4:旋转属性
- (void)XuanZhuan{
    CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform"];
    transformAnima.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
    //CATransform3DIdentity 是单位矩阵,该矩阵没有缩放、旋转、歪斜、透视。把该矩阵应用到图层上面会把图层几何属性修改为默认值
    //沿着Z轴旋转
    transformAnima.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0, 0, 1)];
    //旋转效果累计(即下一次动画执行是否接着刚才的动画)
    transformAnima.cumulative = YES;
    //旋转2遍
    transformAnima.repeatCount = 2;
    transformAnima.duration = 3.0;
    [self.layer addAnimation:transformAnima forKey:nil];
}

//实例6:组合动画CAAnimationGroup
-(void)ZuHeAnimation{
    CAAnimationGroup *animGroup = [CAAnimationGroup animation];
    //缩放
    CABasicAnimation *banScale = [CABasicAnimation animation];
    banScale.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1.5, 1)];
    banScale.duration = 3.0;
    banScale.keyPath = @"transform";
    banScale.removedOnCompletion = NO;
    banScale.fillMode = kCAFillModeForwards;
    //透明
    CABasicAnimation *banOpacity = [CABasicAnimation animationWithKeyPath:@"opacity"];
    banOpacity.fromValue = [NSNumber numberWithFloat:1.0];
    banOpacity.toValue = [NSNumber numberWithFloat:0.1];
    banOpacity.duration = 3.0;
    banOpacity.removedOnCompletion = NO;
    banOpacity.fillMode = kCAFillModeForwards;
    //旋转
    CABasicAnimation *transformAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
    transformAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
    transformAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0, 0, 1)];
    transformAnim.cumulative = YES;
    transformAnim.repeatCount = 2;
    transformAnim.duration = 2.0;
    animGroup.animations = [NSArray arrayWithObjects:self.pathAnimation, banScale, banOpacity, transformAnim, nil];
    animGroup.duration = 5.0;
    [self.layer addAnimation:animGroup forKey:nil];
}
//CAKeyframeAnimation
//CABasicAnimation算是CAKeyFrameAnimation的特殊情况,即不考虑中间变换过程,只考虑起始点与目标点就可以了。而CAKeyFrameAnimation则更复杂一些,允许我们在起点与终点间自定义更多内容来达到我们的实际应用需求,KeyFrame的意思是关键帧,所谓“关键”就是改变物体运动趋势的帧,在该点处物体将发生运动状态,比如矩形的四个角,抛物线的顶点等

-(CAAnimation*)pathAnimation{
    /**
     CAKeyframeAnimation
     
     在画线的时候,方法的内部默认创建一个path。它把路径都放到了path里面去。
     1.创建路径  CGMutablePathRef 调用该方法相当于创建了一个路径,这个路径用来保存绘图信息。
     2.把绘图信息添加到路径里边。
     以前的方法是点的位置添加到ctx(图形上下文信息)中,ctx 默认会在内部创建一个path用来保存绘图信息。
     在图形上下文中有一块存储空间专门用来存储绘图信息,其实这块空间就是CGMutablePathRef。
     3.把路径添加到上下文中。
     */
    CGMutablePathRef path = CGPathCreateMutable();
    
    CGPathMoveToPoint(path,NULL,50.0,120.0);
    CGPathAddLineToPoint(path, NULL, 300, 488);
    CGPathAddCurveToPoint(path,NULL,50.0,275.0,150.0,275.0,150.0,120.0);
    CGPathAddCurveToPoint(path,NULL,150.0,275.0,250.0,275.0,250.0,120.0);
    CGPathAddCurveToPoint(path,NULL,250.0,275.0,350.0,275.0,350.0,120.0);
    CGPathAddCurveToPoint(path,NULL,350.0,275.0,450.0,275.0,450.0,120.0);
    
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    [animation setPath:path];
    [animation setDuration:3.0];
    
    CFRelease(path);
    //ARC的诞生大大简化了我们针对内存管理的开发工作,但是只支持管理 Objective-C 对象, 不支持 Core Foundation 对象。Core Foundation 对象必须使用CFRetain和CFRelease来进行内存管理
    //http://blog.csdn.net/yiyaaixuexi/article/details/8553659
    
    return animation;
}

//绕矩形环跑
- (void)RectRun{
    //新处理一下self.layer
    self.layer.frame = CGRectMake(15, 200, 30, 30);
    self.layer.cornerRadius = 15;
    self.layer.masksToBounds = YES;
    
    //来个帧动画
    CAKeyframeAnimation *rectRunAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    //设定关键帧位置,必须含起始和终止位置
    rectRunAnimation.values = @[[NSValue valueWithCGPoint:self.layer.frame.origin],
                                [NSValue valueWithCGPoint:CGPointMake(320-15, self.layer.frame.origin.y)],
                                [NSValue valueWithCGPoint:CGPointMake(320-15, self.layer.frame.origin.y+100)],
                                [NSValue valueWithCGPoint:CGPointMake(15, self.layer.frame.origin.y+100)],
                                [NSValue valueWithCGPoint:self.layer.frame.origin]];
    //设定每个关键帧的时长,如果没有显示的设置,则默认每个帧的时间=总duration/(values.count - 1)
    rectRunAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0],
                                  [NSNumber numberWithFloat:0.6],
                                  [NSNumber numberWithFloat:0.7],
                                  [NSNumber numberWithFloat:0.8],
                                  [NSNumber numberWithFloat:1]];
    rectRunAnimation.timingFunctions = @[
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear],
                                         [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    //重复次数
    rectRunAnimation.repeatCount = 10;
    //动画结束是否执行逆动画
    rectRunAnimation.autoreverses = NO;
    //线性运动方式
    rectRunAnimation.calculationMode = kCAAnimationLinear;
    //持续时间
    rectRunAnimation.repeatDuration = 4;
    //添加动画
    [self.layer addAnimation:rectRunAnimation forKey:@"rectRunAnimation"];
    
    /**
     CAKeyFrameAnimation的使用中有以下主要的属性需要注意
     (1)values属性
     
     values属性指明整个动画过程中的关键帧点,例如上例中的A-E就是通过values指定的。需要注意的是,起点必须作为values的第一个值。
     
     (2)path属性
     
     作用与values属性一样,同样是用于指定整个动画所经过的路径的。需要注意的是,values与path是互斥的,当values与path同时指定时,path会覆盖values,即values属性将被忽略。例如上述pathAnimation例子
     
     (3)keyTimes属性
     
     该属性是一个数组,用以指定每个子路径(AB,BC,CD)的时间。如果你没有显式地对keyTimes进行设置,则系统会默认每条子路径的时间为:ti=duration/(5-1),即每条子路径的duration相等,都为duration的1\4。当然,我们也可以传个数组让物体快慢结合。例如,你可以传入{0.0, 0.1,0.6,0.7,1.0},其中首尾必须分别是0和1,因此tAB=0.1-0, tCB=0.6-0.1, tDC=0.7-0.6, tED=1-0.7.....
     
     (4)timeFunctions属性
     
     用过UIKit层动画的同学应该对这个属性不陌生,这个属性用以指定时间函数,类似于运动的加速度,有以下几种类型。上例子的AB段就是用了淡入淡出效果。记住,这是一个数组,你有几个子路径就应该传入几个元素
     
     1 kCAMediaTimingFunctionLinear//线性
     2 kCAMediaTimingFunctionEaseIn//淡入
     3 kCAMediaTimingFunctionEaseOut//淡出
     4 kCAMediaTimingFunctionEaseInEaseOut//淡入淡出
     5 kCAMediaTimingFunctionDefault//默认
     
     (5)calculationMode属性
     
     该属性决定了物体在每个子路径下是跳着走还是匀速走,跟timeFunctions属性有点类似
     
     1 const kCAAnimationLinear//线性,默认
     2 const kCAAnimationDiscrete//离散,无中间过程,但keyTimes设置的时间依旧生效,物体跳跃地出现在各个关键帧上
     3 const kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
     4 const kCAAnimationCubic//平均,同上
     5 const kCAAnimationCubicPaced//平均,同上
     
     */
}

代码地址:https://github.com/SPIREJ/SJCoreAnimation

https://www.cnblogs.com/bucengyongyou/archive/2012/12/20/2826590.html

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

推荐阅读更多精彩内容