/*
CAMediaTimng -> CAAnimation ->CAPropertyAnimation(CABasicAnimation(fromValue,toValue);CAKeyframeAnimation(values,path);CAAnimationGroup(animations);CATransition(type;subtype))
1:CAAnimation:核心动画的基础,不能直接使用,赋值动画运行时间,速度的控制,本身实现了CAMediaTiming协议
2:CAPropertyAnimation:属性动画的基类(通过属性进行动画设置,注意是可动画属性),不能直接使用.
3:CAAnimationGroup:动画组,动画组是一种组合模式设计,可以通过动画组来进行所有动画行为的统一控制,组中所有动画效果可以并发执行.
4:CATransition:转场动画,主要通过滤镜进行动画效果设置.
5:CABaseAnimation:基础动画,通过属性修改进行动画参数控制,只有初始状态和结束状态
6:CAKeyframeAnimation:关键帧动画,同样是通过属性进行动画参数控制,但是同基础动画不同的是它可以有多个状态控制
*/
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.darkGray
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.baseAnimation(location: CGPoint(x: 10, y: 0))
}
// MARK: - CABaseAnimation基础动画
fileprivate func baseAnimation(location:CGPoint) {
// 1.创建动画并指定动画属性(你可以为涂层属性(不透明度opacity)设置动画,使其不透明度从0到1淡化,也可以试着如backgroundColor,也可以是动画。 核心动画将在fromValue颜色和toValue颜色之间进行插值创建的动画会将图层的背景颜色从红色渐变为蓝色)
/*
使用CABasicAnimation可操控的几种属性
opacity (透明度)
backgroundColor (背景色)
position (位置)
transform.scale(多种)
rransform.rotation
CALayer Animatable Properties有
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html
动画属性参数说明:
keyPath:动画的运动属性。
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/Key-ValueCodingExtensions/Key-ValueCodingExtensions.html
平移:
- position(点到点坐标)
- position.x或者transform.translation.x(x坐标方向的移动)
- position.y或者transform.translation.y(y坐标方向的移动)
缩放:scale
旋转:rotation
- transform.rotation.x(绕x坐标轴旋转)
- transform.rotation.y(绕y坐标轴旋转)
******************
let basicAnimation = CABasicAnimation(keyPath: "opacity")
// 2.设置动画属性的初始值和结束值
basicAnimation.fromValue = 0
basicAnimation.toValue = 1
*****************
let basicAnimation = CABasicAnimation(keyPath: "backgroundColor")
basicAnimation.fromValue = UIColor.red.cgColor
basicAnimation.toValue = UIColor.blue.cgColor
****************
let basicAnimation = CABasicAnimation(keyPath: "position")
basicAnimation.fromValue = CGPoint.zero
basicAnimation.toValue = location
*****************
// 缩放
let basicAnimation = CABasicAnimation(keyPath: "transform.scale")
basicAnimation.fromValue = 1
basicAnimation.toValue = 0.5
// 旋转
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.x")
basicAnimation.fromValue = Double.pi / 2
basicAnimation.toValue = Double.pi
timingFunction设置动画速度变化
kCAMediaTimingFunctionLinear//匀速的线性计时函数
kCAMediaTimingFunctionEaseIn//缓慢加速,然后突然停止
kCAMediaTimingFunctionEaseOut//全速开始,慢慢减速
kCAMediaTimingFunctionEaseInEaseOut//慢慢加速再慢慢减速
kCAMediaTimingFunctionDefault//也是慢慢加速再慢慢减速,但是它加速减速速度略慢
*/
let basicAnimation = CABasicAnimation(keyPath: "position.x")
basicAnimation.fromValue = 0
basicAnimation.toValue = 100
// 3.设置其他动画属性
// CACurrentMediaTime()图层当前时间
//让动画延迟3秒执行
basicAnimation.beginTime = CACurrentMediaTime() + 3
// 设置动画持续时间
basicAnimation.duration = 3.0
// 设置重复次数
basicAnimation.repeatCount = 1
basicAnimation.fillMode = kCAFillModeForwards
// 运行一次是否移除动画
basicAnimation.isRemovedOnCompletion = false
// // 设定动画的速度变化。
// basicAnimation.timingFunction = CAMediaTimingFunction(name: "kCAMediaTimingFunctionLinear")
// 添加动画到图层,注意key相当于给动画进行命名,以后得到该动画时可以使用此名称获取
self.view.layer.add(basicAnimation, forKey: "scaleAnimation")
}
kCAFillModeBackwards 这个和kCAFillModeForwards是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行.然后就会发现在动画没有开始的时候,只要动画被加入了layer,layer便处于动画初始状态
让动画延迟5秒执行(开始),这样就能看出效果了。
removedOnCompletion:默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
fillMode属性:决定当前对象在非active时间段的行为.比如动画开始之前,动画结束之后
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态(可以理解为动画执行完成后移除)
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
kCAFillModeBackwards 当在动画开始前,你只要把layer加入到一个动画中,layer便立即进入动画的初始状态并等待动画开始.你可以这样设定测试代码,延迟3秒让动画开始,只要动画被加入了layer,layer便处于动画初始状态
let basicAnimation = CABasicAnimation(keyPath: "position.x")
basicAnimation.fromValue = 0
basicAnimation.toValue = 100
// 3.设置其他动画属性
// CACurrentMediaTime()图层当前时间
//让动画延迟3秒执行
basicAnimation.beginTime = CACurrentMediaTime() + 3
// 设置动画持续时间
basicAnimation.duration = 3.0
// 设置重复次数
basicAnimation.repeatCount = 1
basicAnimation.fillMode = kCAFillModeBackwards
// 运行一次是否移除动画
basicAnimation.isRemovedOnCompletion = false
// // 设定动画的速度变化。
// basicAnimation.timingFunction = CAMediaTimingFunction(name: "kCAMediaTimingFunctionLinear")
// 添加动画到图层,注意key相当于给动画进行命名,以后得到该动画时可以使用此名称获取
self.view.layer.add(basicAnimation, forKey: "scaleAnimation")
效果图如下
从效果能看出来kCAFillModeForwards是在动画开始之后layer迅速进入指定位置开始执行动画并在removedOnCompletion = NO的前提下会停在动画结束的最后位置,而kCAFillModeBackwards则是在动画开始之前迅速进入指定状态并在动画开始后执行动画,动画结束后迅速返回到layer的本身位置
kCAFillModeBoth就很好理解了如果removedOnCompletion = NO那layer会在动画开始之前就会迅速进入动画的初始位置并在执行完动画后停在动画结束的位置,如果removedOnCompletion = YES那layer会在动画开始之前就会迅速进入动画的初始位置并在执行完动画后迅速返回到layer的本身位置
执行上面的移动动画,会出现一个现象,那就是结束后图层会到原来的位置
因为图层动画的本质是图层内部的内容转化为位图,经过硬件操作形成的动画效果,其实图层本身在动画过程中没有发生任何变化。
// MARK: - CAKeyframeAnimation关键帧动画
fileprivate func keyframeAnimation(){
//1.创建关键帧动画并设置动画属性
let keyframeAnimation = CAKeyframeAnimation(keyPath: “position”)
//2.设置关键帧,这里有四个关键帧,对于关键帧动画初始值不能省略
let key1 = NSValue(cgPoint: self.view.layer.position)
let key2 = NSValue(cgPoint: CGPoint(x: 80, y: 220))
let key3 = NSValue(cgPoint: CGPoint(x: 45, y: 300))
let key4 = NSValue(cgPoint: CGPoint(x: 55, y: 400))
let array = [key1,key2,key3,key4]
keyframeAnimation.values = array
keyframeAnimation.duration = 8.0
//设置延迟2秒执行
keyframeAnimation.beginTime = CACurrentMediaTime() + 2
//3.添加动画到图层,添加动画后就会执行动画
self.view.layer.add(keyframeAnimation, forKey: “mykeyframeAnimation”)
}