1. 动画组和时间控制
动画组可以对动画进行分组,可以向组中添加多个动画并同时调整持续时间,代理和timingFunction等属性。 对动画进行分组会产生简化的代码,并确保所有动画将作为一个实体单元同步。
这里创建一个CAAnimationGroup
let formGroup = CAAnimationGroup()
formGroup.duration = 0.5
formGroup.fillMode = .backwards
然后创建一个向右移动的动画和变化透明度的动画
let flyRight = CABasicAnimation(keyPath: "position.x")
flyRight.fromValue = -view.bounds.size.width/2
flyRight.toValue = view.bounds.size.width/2
let fadeFieldIn = CABasicAnimation(keyPath: "opacity")
fadeFieldIn.fromValue = 0.25
fadeFieldIn.toValue = 1.0
为formGroup的animations赋值
formGroup.animations = [flyRight, fadeFieldIn]
然后为控件添加上这个动画
heading.layer.add(formGroup, forKey: nil)
formGroup.delegate = self
formGroup.setValue("form", forKey: "name")
formGroup.setValue(username.layer, forKey: "layer")
formGroup.beginTime = CACurrentMediaTime() + 0.3
username.layer.add(formGroup, forKey: nil)
formGroup.setValue(password.layer, forKey: "layer")
formGroup.beginTime = CACurrentMediaTime() + 0.4
password.layer.add(formGroup, forKey: nil)
接下来为登陆按钮添加动画组
let groupAnimation = CAAnimationGroup()
groupAnimation.beginTime = CACurrentMediaTime() + 0.5
groupAnimation.duration = 0.5
groupAnimation.fillMode = .backwards
let scaleDown = CABasicAnimation(keyPath: "transform.scale")
scaleDown.fromValue = 3.5
scaleDown.toValue = 1.0
let rotate = CABasicAnimation(keyPath: "transform.rotation")
rotate.fromValue = .pi / 4.0
rotate.toValue = 0.0
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 0.0
fade.toValue = 1.0
groupAnimation.animations = [scaleDown, rotate, fade]
groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
loginButton.layer.add(groupAnimation, forKey: nil)
2. 图层弹簧动画
下面解释来自于Andy_Ron
2.1 阻尼谐振子
阻尼谐振子,Damped harmonic oscillators(直译就是,逐渐衰弱的振荡器),可以理解为逐渐衰减的振动。
UIKit API简化了弹簧动画的制作,不需要了解它们的原理就可以很方便的使用。 但是,由于您现在是核心动画专家,因此您需要深入研究细节。
钟摆,理想状况下钟摆是不停的摆动,像下面的一样:
对应的运动轨迹图就像:
但现实中由于能量的损耗,钟摆的摇摆的幅度会逐渐减小:
对应的运动轨迹:
这就是一个阻尼谐振子 。
钟摆停下来所需的时间长度,以及最终振荡器图形的方式取决于振荡系统的以下参数:
-
阻尼(damping):由于空气摩擦、机械摩擦和其他作用在系统上的外部减速力。
-
质量(mass):摆锤越重,摆动的时间越长。
-
刚度(stiffness):振荡器的“弹簧”越硬(钟摆的“弹簧”是指地球的引力),钟摆摆动越困难,系统停下来也越快。想象一下,如果在月球或木星上使用这个钟摆;在低重力和高重力情况下的运动将是完全不同的。
-
初始速度(initial velocity):推一下钟摆。
2.2 视图弹簧动画 vs 图层弹簧动画
UIKit以动态方式调整所有其他变量,使系统在给定的持续时间内稳定下来。 这就是为什么UIKit弹簧动画有时有点被迫 停下来的感觉。 如果仔细观察会发现UIKit动画有点不太自然。
幸运的是,核心允许通过CASpringAnimation类为图层属性创建合适的弹簧动画。 CASpringAnimation在幕后为UIKit创建弹簧动画,但是当我们直接调用它时,可以设置系统的各种变量,让动画自己稳定下来。 这种方法的缺点是不能设置固定的持续时间(duration);持续时间取决于提供的其它变量,然后系统计算所得。
CASpringAnimation的一些属性(对应之前振荡系统的参数):
- damping 阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快
- mass 质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大
- stiffness 刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快
- initialVelocity 初始速率,动画视图的初始速度大小。速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反
2.3 图层弹簧动画应用
将之前在animationDidStop的动画
let pulse = CABasicAnimation(keyPath: "transform.scale")
pulse.fromValue = 1.25
pulse.toValue = 1.0
pulse.duration = 0.25
layer?.add(pulse, forKey: nil)
修改为
let pulse = CASpringAnimation(k