iOS CAEmitterLayer 實現粒子發射動畫效果 效果圖 代碼已上傳 GitHub:https://github.com/Silence GitHub/CoreAnimationDemo 動畫效果用 CAEmitterLayer 實現。CAEmitterLayer 顯示粒子發射動畫,具體的 ...
iOS CAEmitterLayer 實現粒子發射動畫效果
效果圖
代碼已上傳 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo
動畫效果用 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
}
}
以上是動畫的實現方法,代碼已上傳 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo
轉載請註明出處:http://www.cnblogs.com/silence-cnblogs/p/6971533.html