android 矢量粒子动画,iOS CAEmitterLayer实现粒子发射动画效果

iOS实现粒子发射动画效果图

a43d7ccb9342ee2a9be84f8cc88db65f.gif

动画效果用 CAEmitterLayer 实现。CAEmitterLayer 显示粒子发射动画,具体的粒子由 CAEmitterCell 封装。代码示例是展示 CAEmitterLayer 如何使用。为了方便,直接在控制器(UIViewController)中设置 CAEmitterLayer。如果在项目中使用,有时在自定义视图(UIView)中加入 CAEmitterLayer 比较合理,例如自定义点赞按钮,可以精简控制器的代码。

下雨动画效果

这里的雨匀速下落,雨的密度逐渐变化。

给控制器添加类型为 CAEmitterLayer 的属性 rainLayer,在 viewDidLoad 方法中对此属性进行初始化

private var rainLayer: CAEmitterLayer!

private func setupRainLayer() {

// 粒子发射图层

rainLayer = CAEmitterLayer()

// 发射器形状为线形,默认发射方向向上

rainLayer.emitterShape = kCAEmitterLayerLine

// 从发射器的轮廓发射粒子

rainLayer.emitterMode = kCAEmitterLayerOutline

// 优先渲染旧的粒子

rainLayer.renderMode = kCAEmitterLayerOldestFirst

// 发射位置

// 对于线形发射器,线的两端点分别为

// (emitterPosition.x - emitterSize.width/2, emitterPosition.y, emitterZPosition)和

// (emitterPosition.x + emitterSize.width/2, emitterPosition.y, emitterZPosition)

rainLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: 0)

// 发射器大小

rainLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)

// 粒子生成速率的倍数,一开始不发射,设置为零

rainLayer.birthRate = 0

// 发射的粒子

let cell = CAEmitterCell()

// 粒子显示的内容,设置CGImage,显示图片

cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage

// 粒子缩放倍数

cell.scale = 0.1

// 粒子寿命,单位是秒

cell.lifetime = 5

// 粒子生成速率,单位是个/秒,实际显示效果要乘以CAEmitterLayer的birthRate

cell.birthRate = 1000

// 粒子速度

cell.velocity = 500

// 粒子发射角度,正值表示顺时针方向

cell.emissionLongitude = CGFloat.pi

// 图层要发射1种粒子

rainLayer.emitterCells = [cell]

// 添加粒子发射图层

view.layer.addSublayer(rainLayer)

}

点击按钮开始或停止动画。用 CABasicAnimation 使粒子生成速率的倍数渐变,达到雨逐渐变大或变小的效果

@IBAction func rainButtonClicked(_ sender: UIButton) {

// 连续调用此方法会影响雨变大或变小的连贯性,所以禁止连续点击按钮

sender.isUserInteractionEnabled = false

// 粒子生成速率渐变动画

let birthRateAnimation = CABasicAnimation(keyPath: "birthRate")

birthRateAnimation.duration = 3

if rainLayer.birthRate == 0 {

// 雨变大

birthRateAnimation.fromValue = 0

birthRateAnimation.toValue = 1

rainLayer.birthRate = 1

} else {

// 雨变小

birthRateAnimation.fromValue = 1

birthRateAnimation.toValue = 0

rainLayer.birthRate = 0

}

// 加入动画

rainLayer.add(birthRateAnimation, forKey: "birthRate")

// 动画时长过后恢复按钮可点击状态

DispatchQueue.main.asyncAfter(deadline: .now() + birthRateAnimation.duration) { [weak self] in

guard self != nil else { return }

sender.isUserInteractionEnabled = true

}

}

发射一圈粒子动画效果

给控制器添加类型为 CAEmitterLayer 的属性 centerHeartLayer,在 viewDidLoad 方法中对此属性进行初始化

private var centerHeartLayer: CAEmitterLayer!

private func setupCenterHeartLayer() {

centerHeartLayer = CAEmitterLayer()

// 发射器形状为圆形,默认向四周发射粒子

centerHeartLayer.emitterShape = kCAEmitterLayerCircle

centerHeartLayer.emitterMode = kCAEmitterLayerOutline

centerHeartLayer.renderMode = kCAEmitterLayerOldestFirst

// 发射器位置

// 对于圆形发射器

// 圆心位于(emitterPosition.x, emitterPosition.y, emitterZPosition)

// 半径为emitterSize.width

centerHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: view.bounds.midY)

centerHeartLayer.emitterSize = centerHeartButton.frame.size

centerHeartLayer.birthRate = 0

let cell = CAEmitterCell()

cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage

cell.lifetime = 1

cell.birthRate = 2000

cell.scale = 0.05

// 粒子缩放倍数每秒减小0.02,粒子逐渐缩小

cell.scaleSpeed = -0.02

// 粒子透明度每秒减小1,粒子逐渐变透明

cell.alphaSpeed = -1

cell.velocity = 30

centerHeartLayer.emitterCells = [cell]

view.layer.addSublayer(centerHeartLayer)

}

点击按钮开始动画

@IBAction func centerHeartButtonClicked(_ sender: UIButton) {

sender.isUserInteractionEnabled = false

// 设置动画开始时间,否则会有太多粒子

centerHeartLayer.beginTime = CACurrentMediaTime()

// 开始生成粒子

centerHeartLayer.birthRate = 1

// 一段时间后停止生成粒子

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

guard let strongSelf = self else { return }

strongSelf.centerHeartLayer.birthRate = 0

}

DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in

guard self != nil else { return }

sender.isUserInteractionEnabled = true

}

}

向上发射一个粒子动画效果

给控制器添加类型为 CAEmitterLayer 的属性 leftHeartLayer,在 viewDidLoad 方法中对此属性进行初始化

private var leftHeartLayer: CAEmitterLayer!

private func setupLeftHeartLayer() {

leftHeartLayer = CAEmitterLayer()

// 点状发射器,默认发射方向向右

// 这句可以省略,点状是默认值

leftHeartLayer.emitterShape = kCAEmitterLayerPoint

// 从发射器中的一点发射粒子

// 这句可以省略,是默认值

leftHeartLayer.emitterMode = kCAEmitterLayerVolume

leftHeartLayer.renderMode = kCAEmitterLayerOldestFirst

// 发射器位置

// 对于点状发射器,发射点在(emitterPosition.x, emitterPosition.y, emitterZPosition)

leftHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX * 0.5, y: view.bounds.midY)

leftHeartLayer.birthRate = 0

let cell = CAEmitterCell()

cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage

cell.scale = 0.5

cell.lifetime = 1

// 1秒发射1个粒子

cell.birthRate = 1

cell.alphaSpeed = -1

cell.velocity = 50

cell.emissionLongitude = -CGFloat.pi / 2

leftHeartLayer.emitterCells = [cell]

view.layer.addSublayer(leftHeartLayer)

}

点击按钮开始动画

@IBAction func leftHeartButtonClicked(_ sender: UIButton) {

sender.isUserInteractionEnabled = false

// 从上1秒开始动画,使按钮点击后立即发射粒子

leftHeartLayer.beginTime = CACurrentMediaTime() - 1

leftHeartLayer.birthRate = 1

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

guard let strongSelf = self else { return }

strongSelf.leftHeartLayer.birthRate = 0

}

DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in

guard self != nil else { return }

sender.isUserInteractionEnabled = true

}

}

向上发射几个粒子动画效果

给控制器添加类型为 CAEmitterLayer 的属性 rightHeartLayer,在 viewDidLoad 方法中对此属性进行初始化

private var rightHeartLayer: CAEmitterLayer!

private func setupRightHeartLayer() {

rightHeartLayer = CAEmitterLayer()

rightHeartLayer.renderMode = kCAEmitterLayerOldestFirst

rightHeartLayer.emitterPosition = CGPoint(x: view.bounds.midX * 1.5, y: view.bounds.midY)

rightHeartLayer.birthRate = 0

let cell = CAEmitterCell()

cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage

cell.scale = 0.5

cell.lifetime = 1

cell.birthRate = 5

cell.alphaSpeed = -1

cell.velocity = 50

cell.emissionLongitude = -CGFloat.pi / 2

// 粒子发射角度的变化范围

cell.emissionRange = CGFloat.pi / 4

rightHeartLayer.emitterCells = [cell]

view.layer.addSublayer(rightHeartLayer)

}

点击按钮开始动画

@IBAction func rightHeartButtonClicked(_ sender: UIButton) {

sender.isUserInteractionEnabled = false

// 1秒发射5个粒子,0.2秒发射1个粒子,从上0.2秒开始动画,使按钮点击后立即发射粒子

rightHeartLayer.beginTime = CACurrentMediaTime() - 0.2

rightHeartLayer.birthRate = 1

DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { [weak self] in

guard let strongSelf = self else { return }

strongSelf.rightHeartLayer.birthRate = 0

}

DispatchQueue.main.asyncAfter(deadline: .now() + 1.6) { [weak self] in

guard self != nil else { return }

sender.isUserInteractionEnabled = true

}

}

抛物线粒子动画效果

实现抛物线动画需要给粒子加上重力加速度。此外,这里还加入粒子旋转效果,同时发射两种粒子。

给控制器添加类型为 CAEmitterLayer 的属性 gravityLayer,在 viewDidLoad 方法中对此属性进行初始化

private var gravityLayer: CAEmitterLayer!

private func setupGravityLayer() {

gravityLayer = CAEmitterLayer()

gravityLayer.renderMode = kCAEmitterLayerOldestFirst

gravityLayer.emitterPosition = CGPoint(x: 0, y: view.bounds.maxY)

gravityLayer.birthRate = 0

let cell = CAEmitterCell()

cell.contents = #imageLiteral(resourceName: "Heart_red").cgImage

cell.scale = 0.5

cell.lifetime = 10

cell.alphaSpeed = -0.1

cell.birthRate = 10

cell.velocity = 100

// y轴方法的加速度,模拟重力加速度

cell.yAcceleration = 20

cell.emissionLongitude = -CGFloat.pi / 4

cell.emissionRange = CGFloat.pi / 4

// 粒子旋转角速度,单位是弧度/秒,正值表示顺时针旋转

// 这句可以省略,默认值是零

cell.spin = 0

// 粒子旋转角速度变化范围

cell.spinRange = CGFloat.pi * 2

let cell2 = CAEmitterCell()

cell2.contents = #imageLiteral(resourceName: "Heart_blue").cgImage

cell2.scale = 0.3

cell2.lifetime = 20

cell2.alphaSpeed = -0.05

cell2.birthRate = 5

cell2.velocity = 135

cell2.yAcceleration = 20

cell2.emissionLongitude = -CGFloat.pi / 4

cell2.emissionRange = CGFloat.pi / 4

cell2.spin = 0

cell2.spinRange = CGFloat.pi * 2

// 图层要发射2种粒子

gravityLayer.emitterCells = [cell, cell2]

view.layer.addSublayer(gravityLayer)

}

点击开始或停止动画

@IBAction func gravityButtonClicked(_ sender: UIButton) {

if gravityLayer.birthRate == 0 {

gravityLayer.beginTime = CACurrentMediaTime()

gravityLayer.birthRate = 1

} else {

gravityLayer.birthRate = 0

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值