iOS Animation - CABasicAnimation与CAKeyframeAnimation
2017-01-12 16:53
477 查看
在 iOS 的 CAAnimation 中 CABasicAnimation、CAKeyframeAnimation的名字如此类似,方法调用也差不多,让较少使用到的开发者些许感到混淆,那我们就来讲讲这两者的区别和联系吧。
首先让我们看看他们的继承图:
很直观的,从上面可以看出CABasicAnimation与CAKeyframeAnimation都继承于CAPropertyAnimation。而CAPropertyAnimation提供了基本的动画属性设置keyPath、additive、cumulative。
iOS Animation-KeyPath值
PS:后面的代码是用swift实现的,那些方法我们都可以用作公共类来调用。
我们可以创建一个CABasicAnimaiton的对象通过keyPath的方式。CABasicAnimation提供了fromValue、toValue、byValue的设置(插值)。它们三个属性定义了一个动画的轨迹,并且最少两个值不能为空。
当设置了CABasicAnimation的起点与终点值后,中间的值都是通过插值方式计算出来的,插值计算是通过timingFunction来指定,timingFunction默认为空,使用liner(匀速运动)。
例如,当我们设置了一个position的动画,设置了开始值PointA与结束值PointB,它们的运动先计算PointA与PointB的中间运动值PointCenter,而PointCenter是由timingFunction来指定值的,并且动画默认是直线匀速运动的。
我们来看看CABasicAnimation的一些简单实现的动画,例如移动、透明度、翻转等等。方法里面传入一个CALayer类或者子类就可以了。
PS:一般做简单动画,最快捷是用KVC给核心动画设置效果,图层里有哪些属性,我们就可以设置哪些属性,具体参考上面的KeyPath值。
CAKeyframeAnimation可以用两种方法定义:CGPath、数组values。
CGPath只对layer的anchorPoint或position属性起作用。
values比较灵活。
keyTimes是一个可选参数,它可以定义keyframe的每个部分,其值是0.0到1.0。keyTimes数组中的每个时间值都对应values中的每一帧,当keyTimes没有设置的时候,各个keyframe的时间是平分的。keyTimes数组中的每个元素定义了相应的keyframe的持续时间值作为动画的总持续时间的一小部分,每个元素的值必须大于、或等于前一个值。
keyframe动画有个重要属性:calculationMode。按照官方的说法,其值可以是’discrete’, ‘linear’, ‘paced’, ‘cubic’和’cubicPaced’。默认值是linear。
calculationMode是对anchorPoint和position进行的动画,当在平面坐标系中有多个离散点的时候,可以是离散,也可以是直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算。下面是对值的解释:
kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;
kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的.
下面我们来看看CAKeyframeAnimation的实例:
让一个layer左右晃动
2.让一个layer圆周(圆圈)运动
首先让我们看看他们的继承图:
很直观的,从上面可以看出CABasicAnimation与CAKeyframeAnimation都继承于CAPropertyAnimation。而CAPropertyAnimation提供了基本的动画属性设置keyPath、additive、cumulative。
iOS Animation-KeyPath值
keyPath值 | 说明 | 值类型 |
---|---|---|
position | 移动位置 | CGPoint |
opacity | 透明度 | 0-1 |
bounds | 变大与位置 | CGRect |
bounds.size | 由小变大 | CGSize |
backgroundColor | 背景颜色 | CGColor |
cornerRadius | 渐变圆角 | 任意数值 |
borderWidth | 改变边框border的粗细 | 任意数值 |
contents | 改变layer内容(图片) | CGImage |
transform.scale | 缩放、放大 | 0.0-1.0 |
transform.rotation.x | 旋转动画(翻转,沿着X轴) | M_PI*n |
transform.rotation.y | 旋转动画(翻转,沿着Y轴) | M_PI*n |
transform.rotation.z | 旋转动画(翻转,沿着Z轴) | M_PI*n |
transform.translation.x | 横向移动(沿着X轴) | 任意数值 |
transform.translation.y | 纵向移动(沿着Y轴) | 任意数值 |
单独解析
1)CABasicAnimation(基础动画)
CABasicAnimation提供了最基础的动画属性设置,是简单的keyframe动画性能。CABasicAnimation可以看做是一种CAKeyframeAnimation的简单动画,因为它只有头尾的关键帧(keyframe)。我们可以创建一个CABasicAnimaiton的对象通过keyPath的方式。CABasicAnimation提供了fromValue、toValue、byValue的设置(插值)。它们三个属性定义了一个动画的轨迹,并且最少两个值不能为空。
当设置了CABasicAnimation的起点与终点值后,中间的值都是通过插值方式计算出来的,插值计算是通过timingFunction来指定,timingFunction默认为空,使用liner(匀速运动)。
例如,当我们设置了一个position的动画,设置了开始值PointA与结束值PointB,它们的运动先计算PointA与PointB的中间运动值PointCenter,而PointCenter是由timingFunction来指定值的,并且动画默认是直线匀速运动的。
我们来看看CABasicAnimation的一些简单实现的动画,例如移动、透明度、翻转等等。方法里面传入一个CALayer类或者子类就可以了。
PS:一般做简单动画,最快捷是用KVC给核心动画设置效果,图层里有哪些属性,我们就可以设置哪些属性,具体参考上面的KeyPath值。
//移动动画position func addLayerAnimationPosition(layer: CALayer) { let animation = CABasicAnimation(keyPath: "position") //开始的位置 animation.fromValue = NSValue(CGPoint: layer.position) //移动到的位置 animation.toValue = NSValue(CGPoint: CGPointMake(120, 200)) //持续时间 animation.duration = 3 //运动后的位置保持不变(layer的最后位置是toValue) animation.removedOnCompletion = false animation.fillMode = kCAFillModeForwards //添加动画 layer.addAnimation(animation, forKey: "addLayerAnimationPosition") } //透明度 opacity func addLayerAnimationOpacity(layer: CALayer) { let animation = CABasicAnimation(keyPath: "opacity") animation.fromValue = 1 animation.toValue = 0 animation.duration = 3 layer.addAnimation(animation, forKey: "addLayerAnimationOpacity") } //变大与位置 bounds func addLayerAnimationBounds(layer:CALayer) { let animation = CABasicAnimation(keyPath: "bounds") animation.toValue = NSValue(CGRect:CGRectMake(130, 200, 140, 140)) animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationBounds") } //由小变大 bounds.size func addLayerAnimationBoundsSize(layer:CALayer) { let animation = CABasicAnimation(keyPath: "bounds.size") animation.fromValue = NSValue(CGSize: layer.bounds.size) animation.toValue = NSValue(CGSize:CGSizeMake(layer.bounds.size.width+20, layer.bounds.size.height+20)) animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationBoundsSize") } //改变颜色 backgroundColor func addLayerAnimationBackgroundColor(layer:CALayer) { let animation = CABasicAnimation(keyPath: "backgroundColor") animation.toValue = UIColor.blueColor().CGColor animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationMargin") } //渐变圆角 cornerRadius func addLayerAnimationCornerRadius(layer:CALayer) { let animation = CABasicAnimation(keyPath: "cornerRadius") animation.toValue = 30 animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationCornerRadius") } //改变边框border的大小(图形周围边框,border默认为黑色), borderWidth func addLayerAnimationBorderWidth(layer:CALayer) { let animation = CABasicAnimation(keyPath: "borderWidth") animation.toValue = 10 animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationBorderWidth") } //改变layer内容(图片),注意如果想要达到改变内容的动画效果,首先在运行动画之前定义好layer的contents contents func addLayerAnimationContents(layer:CALayer) { let animation = CABasicAnimation(keyPath: "contents") let toImage = UIImage.init(named: "通车辆设计矢量素材-06.png")?.CGImage animation.toValue = toImage animation.duration = 3 animation.repeatCount = 1 layer.addAnimation(animation, forKey: "addLayerAnimationBounds") } //缩放、放大 transform.scale func addLayerAnimationTransformScale(layer:CALayer) { let animation = CABasicAnimation(keyPath: "transform.scale") //开始时的倍率 animation.fromValue = 1.0 //结束时的倍率 animation.toValue = 0.5 animation.duration = 3 animation.repeatCount = 1 animation.autoreverses = true layer.addAnimation(animation, forKey: "addLayerAnimationScale") } //旋转动画(翻转,沿着X轴) transform.rotation.x func addLayerAnimationTranformRotationX(layer: CALayer) { let animation = CABasicAnimation(keyPath: "transform.rotation.x") //旋转180度 = PI animation.toValue = M_PI animation.duration = 3 animation.repeatCount = 1 //这里我们可以添加可以不添加,添加一个缓慢进出的动画效果(int/out)。当不添加时,匀速运动,会使用kCAMediaTimingFunctionLinear;当添加时,layer会在开始和结束时比较缓慢 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) layer.addAnimation(animation, forKey: "addLayerAnimationTranformRotationX") } //旋转动画(翻转,沿着Y轴) transform.rotation.y func addLayerAnimationTranformRotationY(layer: CALayer) { let animation = CABasicAnimation(keyPath: "transform.rotation.y") //旋转180度 = PI animation.toValue = M_PI animation.duration = 3 animation.repeatCount = 1 //这里我们可以添加可以不添加,添加一个缓慢进出的动画效果(int/out)。当不添加时,匀速运动,会使用kCAMediaTimingFunctionLinear;当添加时,layer会在开始和结束时比较缓慢 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) layer.addAnimation(animation, forKey: "addLayerAnimationTranformRotationY") } //旋转动画(沿着Z轴) transform.rotation.z func addLayerAnimationTranformRotationZ(layer: CALayer) { let animation = CABasicAnimation(keyPath: "transform.rotation.z") //旋转360度 = PI*2 animation.toValue = M_PI*2 animation.duration = 3 animation.repeatCount = 1 //这里我们可以添加可以不添加,添加一个缓慢进出的动画效果(int/out)。当不添加时,匀速运动,会使用kCAMediaTimingFunctionLinear;当添加时,layer会在开始和结束时比较缓慢 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) layer.addAnimation(animation, forKey: "addLayerAnimationTranformRotationZ") } //横向移动(沿着X轴) transform.translation.x func addLayerAnimationTranformTranslationX(layer: CALayer) { let animation = CABasicAnimation(keyPath: "transform.translation.x") animation.toValue = 20 animation.duration = 3 animation.repeatCount = 1 //这里我们可以添加可以不添加,添加一个缓慢进出的动画效果(int/out)。当不添加时,匀速运动,会使用kCAMediaTimingFunctionLinear;当添加时,layer会在开始和结束时比较缓慢 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) layer.addAnimation(animation, forKey: "addLayerAnimationTranformTranslationX") } //纵向移动(沿着Y轴) transform.translation.y func addLayerAnimationTranformTranslationY(layer: CALayer) { let animation = CABasicAnimation(keyPath: "transform.translation.y") animation.toValue = 20 animation.duration = 3 animation.repeatCount = 1 //这里我们可以添加可以不添加,添加一个缓慢进出的动画效果(int/out)。当不添加时,匀速运动,会使用kCAMediaTimingFunctionLinear;当添加时,layer会在开始和结束时比较缓慢 animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) layer.addAnimation(animation, forKey: "addLayerAnimationTranformTranslationY") }
2)CAKeyframeAnimation(帧动画)
CAKeyframeAnimation提供了通用的keyframe动画功能层的属性给我们使用,它允许我们设置一个特定的数组,这个数组是动画在运动时的值。也就是说,CAKeyframeAnimation支持动画的多个值设置。CAKeyframeAnimation可以用两种方法定义:CGPath、数组values。
CGPath只对layer的anchorPoint或position属性起作用。
values比较灵活。
keyTimes是一个可选参数,它可以定义keyframe的每个部分,其值是0.0到1.0。keyTimes数组中的每个时间值都对应values中的每一帧,当keyTimes没有设置的时候,各个keyframe的时间是平分的。keyTimes数组中的每个元素定义了相应的keyframe的持续时间值作为动画的总持续时间的一小部分,每个元素的值必须大于、或等于前一个值。
keyframe动画有个重要属性:calculationMode。按照官方的说法,其值可以是’discrete’, ‘linear’, ‘paced’, ‘cubic’和’cubicPaced’。默认值是linear。
calculationMode是对anchorPoint和position进行的动画,当在平面坐标系中有多个离散点的时候,可以是离散,也可以是直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算。下面是对值的解释:
kCAAnimationLinear calculationMode的默认值,表示当关键帧为座标点的时候,关键帧之间直接直线相连进行插值计算;
kCAAnimationDiscrete 离散的,就是不进行插值计算,所有关键帧直接逐个进行显示;
kCAAnimationPaced 使得动画均匀进行,而不是按keyTimes设置的或者按关键帧平分时间,此时keyTimes和timingFunctions无效;
kCAAnimationCubic 对关键帧为座标点的关键帧进行圆滑曲线相连后插值计算,对于曲线的形状还可以通过tensionValues,continuityValues,biasValues来进行调整自定义,这里的数学原理是Kochanek–Bartels spline,这里的主要目的是使得运行的轨迹变得圆滑;
kCAAnimationCubicPaced 看这个名字就知道和kCAAnimationCubic有一定联系,其实就是在kCAAnimationCubic的基础上使得动画运行变得均匀,就是系统时间内运动的距离相同,此时keyTimes以及timingFunctions也是无效的.
下面我们来看看CAKeyframeAnimation的实例:
让一个layer左右晃动
func addLayerKeyframeAnimationRock(layer:CALayer) { let animation = CAKeyframeAnimation(keyPath: "position.x") animation.values = [0, 10, -10, 0] //additive设置为true是使Core Animation 在更新 presentation layer 之前将动画的值添加到 model layer 中去。可以看到上面的values是0,10,-10,0. 没有设置的话values=layer.position.x+0, layer.position.x+10, layer.position.x-10 animation.additive = true animation.duration = 0.3 animation.repeatCount = 999999 layer.addAnimation(animation, forKey: "addLayerKeyframeAnimationRock") }
2.让一个layer圆周(圆圈)运动
func addLayerKeyframeAnimationOrbit(layer:CALayer) { let animation = CAKeyframeAnimation(keyPath: "position") let boundingRect = CGRectMake(layer.frame.origin.x, layer.frame.origin.y, 100, 100) animation.path = CGPathCreateWithEllipseInRect(boundingRect,nil) animation.duration = 3 animation.repeatCount = HUGE //其值为kCAAnimationPaced,保证动画向被驱动的对象施加一个恒定速度,不管路径的各个线段有多长,并且无视我们已经设置的keyTimes animation.calculationMode = kCAAnimationPaced //kCAAnimationRotateAuto,确定其沿着路径旋转(具体要自己来体验,这里难解释) animation.rotationMode = kCAAnimationRotateAuto layer.addAnimation(animation, forKey: "addLayerKeyframeAnimationOrbit") }
一句话总结
CABasicAnimation可看做是最多只有2个关键帧的CAKeyframeAnimation相关文章推荐
- iOS CAKeyframeAnimation 示例
- ios-day18-09(使用CAKeyframeAnimation实现对UIView在多个位置之间平移、沿着某一条路径平移)
- IOS开发 CAKeyframeAnimation
- IOS 之 CAKeyframeAnimation
- 【原】iOSCoreAnimation动画系列教程(二):CAKeyFrameAnimation【包会】
- ios-day18-10(使用CAKeyframeAnimation实现图片的抖动效果)
- iOS 核心动画之CAKeyFrameAnimation
- IOS 核心动画之CAKeyframeAnimation - iBaby
- 【原】iOSCoreAnimation动画系列教程(二):CAKeyFrameAnimation【包会】
- ios开发总结之 CAKeyframeAnimation
- iOS CAKeyframeAnimation
- IOS 核心动画之CAKeyframeAnimation - iBaby
- iOS CACoreAnimation :CAKeyframeAnimation
- iOSCoreAnimation CAKeyFrameAnimation 详解
- iOS动画:UIView动画和CALayer动画(CABasicAnimation、CAKeyframeAnimation的使用)
- 猫猫学IOS(四十)UI之核心动画_抖动效果_CAKeyframeAnimation
- iOS动画:UIView动画和CALayer动画(CABasicAnimation、CAKeyframeAnimation的使用)
- 猫猫学IOS(四十)UI之核心动画_抖动效果_CAKeyframeAnimation
- IOS Animation-CAKeyframeAnimation例子(简单动画实现)
- IOS图像4之CoreAnimation:CABaseAnimation、CAKeyframeAnimation、CAanimationGroup、CATrainsition