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

2020-01-20 13:20:30丽君

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

iOS,CAEmitterLayer,粒子发射

代码已上传 GitHub:https://www.easck.com// 从发射器的轮廓发射粒子 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)
}