··~~~~因为工作原因需要对动画有所了解,由于之前用的很少,这方面的知识很匮乏,所以借此机会深入的了解了下关于动画方面的知识,由于没有找到好的动画效果,就高仿了一个用CAKeyframeAnimation实现的过山车动画~~~~~~~呜呜呜
动态果图:http://ww4.sinaimg.cn/large/006tNbRwgw1f53ahi8vslg30if0a8e81
项目中主要用到的类
- CAShapeLayer
- CAGradientLayer
- CAKeyframeAnimation
渐变的天空背景色使用CAGradientLayer类来生成两种或更多的渐变平滑的颜色,草坪和轨道使用CAShapeLayer配合UIBezierPath(贝塞尔曲线)完成,云朵、大地和大树可以通过CALayer设置contents属性来实现(注:如果给CALayer设置color或imaeg属性时,需要将color转换为CGColor,image转换为CGImage,不然图片或颜色不显示---),云朵和过山车的动画可以使用CAKeyframeAnimation来实现,是不是看起来好简单~~~~
---------------------------------下面是每个类的功能介绍---------------------------------
CAShapeLayer
- 1、CAShapeLayer是一种特殊的层,可以在上面渲染图形。
- 2、CAShapeLayer继承自CALayer,可使用CALayer的所有属性。
- 3、CAShapeLayer需要和贝塞尔曲线配合使用才有意义,贝塞尔曲线为其提供渲染的图形。
- 4、使用CAShapeLayer与贝塞尔曲线可以实现不再view的drawRect方法中画出一些想要的图形。
CAShapeLayer是一个通过矢量图形而不是bitmap来绘制的图层子类, CAShapeLayer相当于使用画笔直接在图层上绘制想要的图片,通过GPU来渲染图形,如果使用drawRect来绘制图形是调用CoreGraphics框架中得方法,占用CPU,消耗性能大(那简直要卡爆了)。使用CAShapeLayer你可以指定诸如颜色和线宽等属性,用CGPath来定义想要绘制的图形,最后CAShapeLayer就自动渲染出来了。当然,你也可以用Core Graphics直接向原始的CALyer的内容中绘制一个路径,相比直下,使用CAShapeLayer有以下一些优点:
- 渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
- 高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
- 不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉
- 不会出现像素化。当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。
使用CAShapeLayer来绘制草地的代码:
//第一块草坪
self.shapeLayer = [CAShapeLayer layer];
//通过贝塞尔曲线绘制路径
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, kScreenWidth - 20)];//设置曲线的起点
[path addLineToPoint:CGPointMake(0, kScreenWidth - 100)];//连线到某点
[path addQuadCurveToPoint:CGPointMake(kScreenHeight / 3.0, kScreenWidth - 20) controlPoint:CGPointMake(kScreenHeight / 6.0, kScreenWidth - 100)];//设置终点和控制点,控制点越小绘制的图形越大越高
self.shapeLayer.path = path.CGPath;
self.shapeLayer.fillColor = [UIColor colorWithRed:82.0/255.0 green:177.0/255.0 blue:44.0/255.0 alpha:1.0].CGColor;//设置填充色
[self.backV.layer addSublayer:self.shapeLayer];
//第二块草坪
CAShapeLayer *shapeLayer2 = [CAShapeLayer layer];
UIBezierPath *path2 = [UIBezierPath bezierPath];
[path2 moveToPoint:CGPointMake(0, kScreenWidth - 20)];
[path2 addQuadCurveToPoint:CGPointMake(kScreenHeight, kScreenWidth - 60) controlPoint:CGPointMake(kScreenHeight / 2.0, kScreenWidth - 150)];
[path2 addLineToPoint:CGPointMake(kScreenHeight, kScreenWidth - 20)];
shapeLayer2.path = path2.CGPath;
shapeLayer2.fillColor = [UIColor colorWithRed:92.0/255.0 green:195.0/255.0 blue:52.0/255.0 alpha:1.0].CGColor;
[self.backV.layer addSublayer:shapeLayer2];
效果图:
CAGradientLayer
CAGradientLayer 简介
- CAGradientLayer是CALayer图层类的子类,用于处理渐变色的层结构。
- CAGradientLayer的渐变色可以做隐式动画。
- CAGradientLayer和CAShapeLayer配合使用可实现复杂效果。
- CAGradientLayer可以用作PNG的遮罩效果。
- CAGradientLayer 坐标系统
- CAGradientLayer的坐标系统是从坐标(0,0)到(1,1)绘制的矩形。
- CAGradientLayer的frame值的size不为正方形的话,坐标系统会被拉伸。
- CAGradientLayer的startPoint与endPoint会直接影响颜色的绘制方向。
- CAGradientLayer的颜色分割点是以0~1的比例来计算的,颜色分割点为渐变色开始或终止的地方。
CAGradientLayer 属性介绍
- colors:渐变颜色数组
- locations:渐变颜色的区间分布(分割点),locations的数组长度和colors一致。这个属性可不设,默认是nil,系统会平均分布颜色如果有特定需要可设置,数组设置为0 ~ 1之间单调递增。
- startPoint:映射locations中起始位置,用单位向量表示。比如(0, 0)表示从左上角开始变化。默认值是:(0.5, 0.0)。
- endPoint:映射locations中结束位置,用单位向量表示。比如(1, 1)表示到右下角变化结束。默认值是:(0.5, 1.0)。
- type:默认值是kCAGradientLayerAxial,表示按像素均匀变化。
使用CAGradientLayer来实现了项目中天空背景的绘制,效果图:
天空背景代码:
//初始化 背景
self.CAGLayer = [CAGradientLayer layer];
self.CAGLayer.frame = self.backV.bounds;
//设置渐变的颜色
self.CAGLayer.colors = @[(id)[UIColor colorWithRed:178.0/255.0 green:226.0/255.0 blue:248.0/255.0 alpha:1.0].CGColor,
(id)[UIColor colorWithRed:232.0/255.0 green:244.0/255.0 blue:193.0/255.0 alpha:1.0].CGColor];
//设置渐变的方向 自左上到右下
self.CAGLayer.startPoint = CGPointMake(0, 0);
self.CAGLayer.endPoint = CGPointMake(1, 1);
[self.backV.layer addSublayer: self.CAGLayer];
CAKeyframeAnimation
CAKeyframeAnimation简介
- CAKeyframeAnimation又称关键帧动画
- CAKeyframeAnimation是抽象类CAPRopertyAnimation的子类,可以直接使用
- 通过values与path两个属性指定动画属性
注意事项
- 若指定了path属性,则values属性将被忽略
- CABasicAnimation相当于只有两个关键帧的CAKeyframeAnimation
CAKeyframeAnimation 属性介绍
- values(NSArray *)存放关键帧的多个值,类似于CABasicAnimation的fromValue与toValue值
- path(CGPathRef)动画的执行路径,可以通过绘图的方式绘制路径
- keyTimes(NSArray *)每个关键帧的执行时间,类型为NSNumber类型,若不指定,则所有的关键帧平分动画的duration时长
- timingFunctions(NSArray *)速度控制函数数组
- calculationMode(NSString *)指定关键帧的动画属性,若指定该值,则keyTimes与timingFunctions属性值将被忽略,默认为:kCAAnimationLinear
- rotationMode(NSString *)指定旋转模式,默认为nil
CAKeyframeAnimation类为对象提供了关键帧动画的功能。你创建一个CAKeyframeAnimation对象使用animationWithKeyPath:指定属性的关键路径,你可以指定要使用关键帧的值来控制时间和动画的行为。我们可以通过CAKeyframeAnimation来实现过山车在轨道上的的动画和云朵的动画:
代码如下:
CALayer *carLayer = [CALayer layer];
carLayer.frame = CGRectMake(0, 0, 17, 11);
UIImage *image = [UIImage imageNamed:@"othercar"];
CGImageRef imageRef = image.CGImage;
carLayer.contents = (__bridge id _Nullable)(imageRef);
UIBezierPath *bluePath = [UIBezierPath bezierPath];
bluePath.lineCapStyle = kCGLineCapRound;
bluePath.lineJoinStyle = kCGLineCapRound;
[bluePath moveToPoint:CGPointMake(kScreenWidth2 +10, kScreenHeight2 - 7)];
[bluePath addLineToPoint:CGPointMake(kScreenWidth2 + 10, kScreenHeight2 - 77)];
[bluePath addQuadCurveToPoint:CGPointMake(kScreenWidth2 / 1.8, kScreenHeight2 - 77) controlPoint:CGPointMake(kScreenWidth2 - 120, 193)];
[bluePath addArcWithCenter:CGPointMake(kScreenWidth2 / 1.9, kScreenHeight2 - 140) radius:63 startAngle:0.5*M_PI endAngle:2.5*M_PI clockwise:true];
[bluePath addCurveToPoint:CGPointMake(0, kScreenHeight2 - 107) controlPoint1:CGPointMake(kScreenWidth2 /1.8 - 60, kScreenHeight2 - 67) controlPoint2:CGPointMake(150, kScreenHeight2 /2.3 -7)];
[bluePath addLineToPoint:CGPointMake(-100, kScreenHeight2 +7)];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];//简单的创建一个带路径的动画效果,比较粗糙
animation.path = bluePath.CGPath;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];//CAMediaTiming协议定义了在一段动画内用来控制逝去时间的属性的集合,CALayer和CAAnimation都实现了这个协议,所以时间可以被任意基于一个图层或者一段动画的类控制。
// 速度控制函数(CAMediaTimingFunction)
// 1.kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
// 2.kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加速离开
// 3.kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的到达目的地
// 4.kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。
animation.duration = 6;//动画持续时间
animation.beginTime = begintime;
animation.repeatCount = MAXFLOAT;
animation.autoreverses =false;
animation.calculationMode = kCAAnimationCubicPaced;//自动计算
animation.rotationMode = kCAAnimationRotateAuto;//动画角度自动调整
[self.view.layer addSublayer:carLayer];
[carLayer addAnimation:animation forKey:@"carAnimation"];