天天看點

android 矢量粒子動畫,iOS CAEmitterLayer實作粒子發射動畫效果

iOS實作粒子發射動畫效果圖

android 矢量粒子動畫,iOS CAEmitterLayer實作粒子發射動畫效果

動畫效果用 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

}

}

以上就是本文的全部内容,希望對大家的學習有所幫助,也希望大家多多支援腳本之家。