语音输入时,有没有考虑过下面两种波浪形动画是怎么生成的呢?
没错,它就是我们今天需要了解的,图层复制动画CAReplicatorLayer。
首先我们先来看一个例子。
1.将CALayer复制多次添加到CAReplicatorLayer图层上面
创建属性
let replicator = CAReplicatorLayer()//复制图层(父图层)
let dot = CALayer()//显示图层(子图层)
let dotLength: CGFloat = 6.0//子图层的宽高
let dotOffset: CGFloat = 8.0//子图层的偏移量
将图层在viewDidLoad里面添加到view.layer上面
replicator.frame = view.bounds//让replicator层和viewController坐标相同
view.layer.addSublayer(replicator)
dot.frame = CGRect(x: replicator.frame.size.width - dotLength, y: replicator.position.y, width: dotLength, height: dotLength)//设置子图层的坐标,x坐标居右,y坐标为屏幕中间位置
dot.backgroundColor = UIColor.lightGray.cgColor
dot.borderColor = UIColor(white: 1.0, alpha: 1.0).cgColor
dot.borderWidth = 0.5
dot.cornerRadius = 1.5
replicator.addSublayer(dot)//将子图层添加到replicator层
replicator.instanceCount = Int(view.frame.size.width / dotOffset)//根据屏幕宽度,设置copy数量
replicator.instanceTransform = CATransform3DMakeTranslation(-dotOffset, 0.0, 0.0)//设置偏移量,让所有的copy都显示在屏幕上
运行效果
添加动画
// This is a test animation, you're going to delete it
let move = CABasicAnimation(keyPath: "position.y")
move.fromValue = dot.position.y
move.toValue = dot.position.y - 50.0
move.duration = 1.0
move.repeatCount = 10
dot.add(move, forKey: nil)
// This is the end of the code you're going to delete
replicator.instanceDelay = 0.02//每个copy延迟0.02秒执行动画
运行效果
删除上面的测试动画,现在我们来创建一个波浪形动画。
在开始语音输入时,添加Scale动画:
let scale = CABasicAnimation(keyPath: "transform")
scale.fromValue = NSValue(caTransform3D: CATransform3DIdentity)
scale.toValue = NSValue(caTransform3D: CATransform3DMakeScale(1.4, 15, 1.0))
scale.duration = 0.33
scale.repeatCount = .infinity
scale.autoreverses = true
scale.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
dot.add(scale, forKey: "dotScale")
运行效果
添加Opacity动画
let fade = CABasicAnimation(keyPath: "opacity")
fade.fromValue = 1.0
fade.toValue = 0.2
fade.duration = 0.33
fade.beginTime = CACurrentMediaTime() + 0.33
fade.repeatCount = .infinity
fade.autoreverses = true
fade.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
dot.add(fade, forKey: "dotOpacity")
运行效果
添加Tint动画
let tint = CABasicAnimation(keyPath: "backgroundColor")
tint.fromValue = UIColor.magenta.cgColor
tint.toValue = UIColor.cyan.cgColor
tint.duration = 0.66
tint.beginTime = CACurrentMediaTime() + 0.28
tint.fillMode = kCAFillModeBackwards
tint.repeatCount = .infinity
tint.autoreverses = true
tint.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
dot.add(tint, forKey: "dotColor")
运行效果
前面我们对CAReplicatorLayer的子图层进行了一系列动画,我们也可以对CAReplicatorLayer本身添加一些动画,除了一些基本的position、backgroundColor、cornerRadius属性等等可以添加动画以外,它本身还有一些独有的属性可以添加动画,比如:instanceDelay、instanceTransform、instanceColor、instanceRedOffset、instanceGreenOffset、instanceBlueOffset、instanceAlphaOffset
添加动画:
let initialRotation = CABasicAnimation(keyPath: "instanceTransform.rotation")
initialRotation.fromValue = 0.0
initialRotation.toValue = 0.01
initialRotation.duration = 0.33
initialRotation.isRemovedOnCompletion = false
initialRotation.fillMode = kCAFillModeBackwards
initialRotation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
replicator.add(initialRotation, forKey: "initialRotation")
let rotation = CABasicAnimation(keyPath: "instanceTransform.rotation")
rotation.fromValue = 0.01
rotation.toValue = -0.01
rotation.duration = 0.99
rotation.beginTime = CACurrentMediaTime() + 0.33
rotation.repeatCount = .infinity
rotation.autoreverses = true
rotation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
replicator.add(rotation, forKey: "replicatorRotation")
运行效果
移除动画
replicator.removeAllAnimations()
这个remove方法仅仅移除了replicator的instanceTransform动画。
下一步将dot还原到原始的大小
let scale = CABasicAnimation(keyPath: "transform")
scale.toValue = NSValue(caTransform3D: CATransform3DIdentity)
scale.duration = 0.33
scale.isRemovedOnCompletion = false
scale.fillMode = kCAFillModeForwards
dot.add(scale, forKey: nil)
该动画不需要指定fromValue,Core Animation将自动从当前值缩放到toValue大小
然后移除dotColor和dotOpacity动画
dot.removeAnimation(forKey: "dotColor")
dot.removeAnimation(forKey: "dotOpacity")
dot.backgroundColor = UIColor.lightGray.cgColor
speakButton.isHidden = false
回到最初状态