Swift Animation 内容层动画(三)

Posted by Calvin on 2017-06-25

CAEmitterCell 粒子动画

在 iOS 系统中,粒子系统有2部分组成:CAEmitterLayer 和 CAEmitterCell。

(1)CAEmitterLayer 为粒子发射图层。该图层主要用于控制粒子展现范围、粒子发射位置、粒子发射形状、渲染模式等属性。通过 CAEmitterCell 构建的发射单元都受到 CAEmitterLayer 图层节制,可以说粒子展现必须在 CAEmitterLayer 图层上实现。

(2)CAEmitterCell 粒子发射单元,用于对粒子系统中的单个粒子做更加精细的控制。比如控制粒子的移动速度、方向、范围。在 CAEmitterCell 类中提供类几十种粒子属性参数设置,所以结合这些属性可以制作各种炫酷的粒子特效动画。

粒子火焰效果

1.birthRate:表示火焰效果中每秒粒子的组成个数,个数越多,火焰越大越逼真。
2.velocity:表明当前粒子速度信息,不同的粒子速度控制火焰的燃烧剧烈程度以及火焰的燃烧方向。

还有很多的属性设置才能实现火焰的效果,下面直接贴上实现代码。

override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black
let emitterCell = CAEmitterCell()
emitterCell.name = "fire"
emitterCell.emissionLongitude = CGFloat(M_PI)// emissionLongitude:x-y 平面的 发 射方向
emitterCell.velocity = -1// 粒子速度 负数表明向上燃烧
emitterCell.velocityRange = 50// 粒子速度范围
emitterCell.emissionRange = 1.1//周围发射角度
emitterCell.yAcceleration = -200// 粒子y方向的加速度分量
emitterCell.scaleSpeed = 0.3// 缩放比例 超大火苗
emitterCell.color = UIColor(red: 0 ,green: 0.4 ,blue:0.2 ,alpha:0.1).cgColor
emitterCell.contents = UIImage(named: "fire.png")!.cgImage
let emitterLayer = CAEmitterLayer()
emitterLayer.position = self.view.center// 粒子发射位置
emitterLayer.emitterSize = CGSize(width: 50, height: 10)// 控制火苗大小
emitterLayer.renderMode = kCAEmitterLayerAdditive
emitterLayer.emitterMode = kCAEmitterLayerOutline// 控制发射源模式 即形状
emitterLayer.emitterShape = kCAEmitterLayerLine
emitterLayer.emitterCells = [emitterCell]
self.view.layer.addSublayer(emitterLayer)
emitterLayer.setValue(500, forKeyPath: "emitterCells.fire.birthRate")
emitterLayer.setValue(1, forKeyPath: "emitterCells.fire.lifetime")
}

效果如下:

20170625149838384979586.gif

霓虹效果实现

霓虹效果实现和火焰燃烧类似,都是通过 iOS 粒子来进行描述的。

override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black
let emitterCell = CAEmitterCell()
emitterCell.name = "nenolight"
emitterCell.emissionLongitude = CGFloat(M_PI*2)// emissionLongitude:x-y 平面的 发 射方向
emitterCell.velocity = 50// 粒子速度
emitterCell.velocityRange = 50// 粒子速度范围
emitterCell.scaleSpeed = -0.2// 缩放比例 超大火苗
emitterCell.scale = 0.1
emitterCell.greenSpeed = -0.1
emitterCell.redSpeed = -0.2
emitterCell.blueSpeed = 0.1
emitterCell.alphaSpeed = -0.2
emitterCell.birthRate = 100
emitterCell.lifetime = 4
emitterCell.color = UIColor.white.cgColor
emitterCell.contents = UIImage(named: "neonlight.png")!.cgImage
let emitterLayer = CAEmitterLayer()
emitterLayer.position = self.view.center// 粒子发射位置
emitterLayer.emitterSize = CGSize(width: 2, height: 2)// 控制粒子大小
emitterLayer.renderMode = kCAEmitterLayerBackToFront
emitterLayer.emitterMode = kCAEmitterLayerOutline// 控制发射源模式 即形状
emitterLayer.emitterShape = kCAEmitterLayerCircle
emitterLayer.emitterCells = [emitterCell]
self.view.layer.addSublayer(emitterLayer)
}

效果如下:

20170625149838418551319.gif

CoreAnimation:CAGradientLayer

CAGradientLayer 追本溯源

CAGradientLayer 可以拆解为3个主要部分:CA、Gradient、Layer。

  1. CA 为 CoreAnimation 的缩写。
  2. Gradient 为梯度的意思,描述了当前动画的特点,实现一些梯度功能的动画效果。比如位置的梯度变化、颜色的梯度渐变等。
  3. Layer表明当前动画并非直接作用于 UIView 显示层上,而是作用在 Layer 内容层。

光波效果实现原理分析

通过对动画的分解,基本上可以弄清楚动画的演变过程。

  1. 光波的执行方向。
  2. 光波的颜色梯度。
  3. 光波的”彗星拖尾”效果。

光波方向

光波从上到下的扫描效果:

// 设置光波起始位置和终止位置坐标
gradientLayer.startPoint = CGPoint(x:0,y:0)
gradientLayer.endPoint = CGPoint(x:1,y:0)

光波梯度

let color = UIColor(red:216/255.0,green:114/255.0,blue:213/255.0,alpha:1.0) // 粉色
let color1 = UIColor(red:61/255.0,green:226/255.0,blue:210/255.0,alpha:1.0) // 青色
// 设置光波颜色梯度
gradientLayer:colors = [UIColor.clear.cgColor,color1.cgColor,color.cgColor];

光波”彗星拖尾”效果

let color = UIColor(red:216/255.0,green:114/255.0,blue:213/255.0,alpha:1.0) // 粉色
let color1 = UIColor(red:61/255.0,green:226/255.0,blue:210/255.0,alpha:1.0) // 青色
// 设置光波颜色梯度
gradientLayer:colors = [UIColor.clear.cgColor,color1.cgColor,color.cgColor];
gradientLayer.locations = [0.0,0.1,0.2]

其中 locations 为颜色渐变比例数组。

光波扫描效果

let gradientAnimation:CABasicAnimation = CABasicAnimation()
gradientAnimation.keyPath = 'locations' // 动画属性
gradientAnimation.fromValue = [0.0,0.1,0.2]; // 动画属性变化起始状态
gradientAnimation.toValue = [0.8,0.9,1.0]; // 动画属性变化终止状态值
gradientAnimation.duration = 3.0; // 动画执行周期
gradientAnimation.repeatCount = 10; // 动画执行重复次数
gradientLayer.add(gradientAnimation,forKey:nil) // 将基础动画添加到 Layer 图层

指纹扫描动画

override func viewDidLoad() {
super.viewDidLoad()
// part1:设置指纹扫描背景图片
let image:UIImage = UIImage(named: "unLock.jpg")!
let imageView:UIImageView = UIImageView(image: image)
imageView.contentMode = UIViewContentMode.scaleAspectFit
imageView.frame = self.view.bounds
imageView.center = self.view.center
self.view.backgroundColor = UIColor.black
self.view.addSubview(imageView)
// part2:设置Layer图层属性
let gradientLayer:CAGradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x: 105, y: 330, width: 200,height: 200)
imageView.layer.addSublayer(gradientLayer)
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = CGPoint(x: 0, y: 1)
gradientLayer.colors = [UIColor.clear.cgColor,UIColor.white.cgColor,UIColor.clear.cgColor]
gradientLayer.locations = [0.0,0.1,0.2]
// part3:设置CABasicAnimation
let gradientAnimation:CABasicAnimation = CABasicAnimation()
gradientAnimation.keyPath = "locations"
gradientAnimation.fromValue = [0.0,0.1,0.2];
gradientAnimation.toValue = [0.8,0.9,1.0];
gradientAnimation.duration = 3.0;
gradientAnimation.repeatCount = 10;
gradientLayer.add(gradientAnimation, forKey: nil)
}

效果如下:

20170625149838566182232.gif

音量条跳动效果

设计思路:

  1. 动画起始阶段:15根柱状 UIView 视图和一组随机颜色
  2. 动画进行阶段
  3. 动画结束阶段

动画起始阶段

func setcolorArray(){
colorArray = NSMutableArray()
let color1:UIColor = UIColor(red: 255.0 / 255.0, green: 127.0 / 255.0, blue: 79.0 / 255.0, alpha: 1.0)
let color2:UIColor = UIColor(red: 138.0 / 255.0, green: 206.0 / 255.0, blue: 245.0 / 255.0, alpha: 1.0)
let color3:UIColor = UIColor(red: 216.0 / 255.0, green: 114.0 / 255.0, blue: 213.0 / 255.0, alpha: 1.0)
let color4:UIColor = UIColor(red: 51.0 / 255.0, green: 207.0 / 255.0, blue: 48.0 / 255.0, alpha: 1.0)
let color5:UIColor = UIColor(red: 102.0 / 255.0, green: 150.0 / 255.0, blue: 232.0 / 255.0, alpha: 1.0)
let color6:UIColor = UIColor(red: 255.0 / 255.0, green: 105.0 / 255.0, blue: 177.0 / 255.0, alpha: 1.0)
let color7:UIColor = UIColor(red: 187.0 / 255.0, green: 56.0 / 255.0, blue: 201.0 / 255.0, alpha: 1.0)
let color8:UIColor = UIColor(red: 255.0 / 255.0, green: 163.0 / 255.0, blue: 0.0 / 255.0, alpha: 1.0)
let color9:UIColor = UIColor(red: 203.0 / 255.0, green: 93.0 / 255.0, blue: 92.0 / 255.0, alpha: 1.0)
let color10:UIColor = UIColor(red: 61.0 / 255.0, green: 226.0 / 255.0, blue: 210.0 / 255.0, alpha: 1.0)
let color11:UIColor = UIColor(red: 25.0 / 255.0, green: 146.0 / 255.0, blue: 255.0 / 255.0, alpha: 1.0)
colorArray.add(color1)
colorArray.add(color2)
colorArray.add(color3)
colorArray.add(color4)
colorArray.add(color5)
colorArray.add(color6)
colorArray.add(color7)
colorArray.add(color8)
colorArray.add(color9)
colorArray.add(color10)
colorArray.add(color11)
}
var audioBarNum:Int = 0
var gradientLayer:CAGradientLayer = CAGradientLayer()
var layerArray:NSMutableArray = NSMutableArray()
var colorArray:NSMutableArray = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
setcolorArray()
self.view.backgroundColor = UIColor.black
audioBarNum = 15;
for i in 0...audioBarNum {
let h:CGFloat = 150
let w:CGFloat = (self.view.frame.size.width-10)/CGFloat(audioBarNum)
let x:CGFloat = 20
let y:CGFloat = 50
let view:UIView = UIView(frame: CGRect(x: w*CGFloat(i)+x, y: y, width: w-x, height: h))
self.view.addSubview(view)
gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds;
gradientLayer.startPoint = CGPoint(x: 0, y: 0);
gradientLayer.endPoint = CGPoint(x: 0, y: 1);
view.layer.addSublayer(gradientLayer)
layerArray.add(gradientLayer)
}
Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(ViewController.colorChange), userInfo: nil, repeats: true)
}

动画进行阶段

for i in 0...audioBarNum {
let h:CGFloat = 150
let w:CGFloat = (self.view.frame.size.width-10)/CGFloat(audioBarNum)
let x:CGFloat = 20
let y:CGFloat = 50
let view:UIView = UIView(frame: CGRect(x: w*CGFloat(i)+x, y: y, width: w-x, height: h))
self.view.addSubview(view)
gradientLayer = CAGradientLayer()
gradientLayer.frame = view.bounds;
gradientLayer.startPoint = CGPoint(x: 0, y: 0);
gradientLayer.endPoint = CGPoint(x: 0, y: 1);
view.layer.addSublayer(gradientLayer)
layerArray.add(gradientLayer)
}
func colorChange(){
for layer in layerArray{
let index:Int = Int(arc4random_uniform(11))
let color:UIColor = colorArray.object(at: index) as! UIColor
let colors = [
UIColor.clear.cgColor,
color.cgColor
]
let layer = layer as! CAGradientLayer
layer.colors = colors
layer.locations = [0,1.0]
let gradientAnimation:CABasicAnimation = CABasicAnimation()
gradientAnimation.keyPath = "locations"
let beginValue = Float(arc4random_uniform(11))/10.0
gradientAnimation.fromValue = [beginValue,beginValue]
gradientAnimation.toValue = [1.0,1.0]
gradientAnimation.duration = 0.4
layer.add(gradientAnimation, forKey: nil)
}
}

动画结束

可以设置动画运行时间或者其他事件后关闭动画效果

效果如下:

20170625149838628934794.gif

本文代码1:点击查看

本文代码2:点击查看