全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

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

代码已上传 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

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


# iOS  # CAEmitterLayer  # 粒子发射  # iOS实现自定义起始时间选择器视图  # iOS中 UIActionSheet字体的修改  # IOS 获取网络图片大小实例详解  # IOS中UIWebView、WKWebView之JS交互  # IOS打开照相机与本地相册选择图片实例详解  # 图层  # 对此  # 重力加速度  # 这句  # 变大  # 默认值  # 自定义  # 上传  # 几个  # 是个  # 会有  # 太多  # 两种  # 分别为  # 如何使用  # 时长  # 大家多多  # 为零  # 显示效果  # 顺时针 


相关文章: 学校免费自助建站系统:智能生成+拖拽设计+多端适配  怎么将XML数据可视化 D3.js加载XML  宁波自助建站系统如何快速打造专业企业网站?  如何正确选择百度移动适配建站域名?  如何快速辨别茅台真假?关键步骤解析  北京网站制作公司哪家好一点,北京租房网站有哪些?  子杰智能建站系统|零代码开发与AI生成SEO优化指南  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  如何选择美橙互联多站合一建站方案?  C#如何使用XPathNavigator高效查询XML  建站主机默认首页配置指南:核心功能与访问路径优化  郑州企业网站制作公司,郑州招聘网站有哪些?  魔方云NAT建站如何实现端口转发?  关于BootStrap modal 在IOS9中不能弹出的解决方法(IOS 9 bootstrap modal ios 9 noticework)  建站之星后台密码遗忘?如何快速找回?  已有域名建站全流程解析:网站搭建步骤与建站工具选择  定制建站如何定义?其核心优势是什么?  威客平台建站流程解析:高效搭建教程与设计优化方案  建站主机是否属于云主机类型?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  制作网站哪家好,cc、.co、.cm哪个域名更适合做网站?  深圳网站制作培训,深圳哪些招聘网站比较好?  新网站制作渠道有哪些,跪求一个无线渠道比较强的小说网站,我要发表小说?  电商网站制作公司有哪些,1688网是什么意思?  外贸公司网站制作哪家好,maersk船公司官网?  建站之星展会模版如何一键下载生成?  小视频制作网站有哪些,有什么看国内小视频的网站,求推荐?  如何通过wdcp面板快速创建网站?  小建面朝正北,A点实际方位是否存在偏差?  如何在万网主机上快速搭建网站?  香港服务器建站指南:免备案优势与SEO优化技巧全解析  如何快速上传自定义模板至建站之星?  制作网站的网址是什么,请问后缀为.com和.com.cn还有.cn的这三种网站是分别是什么类型的网站?  北京网站制作网页,网站升级改版需要多久?  XML的“混合内容”是什么 怎么用DTD或XSD定义  北京营销型网站制作公司,可以用python做一个营销推广网站吗?  盘锦网站制作公司,盘锦大洼有多少5G网站?  建站之星免费模板:自助建站系统与智能响应式一键生成  家庭建站与云服务器建站,如何选择更优?  如何快速搭建高效WAP手机网站吸引移动用户?  手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?  ppt制作免费网站有哪些,ppt模板免费下载网站?  如何选择适合PHP云建站的开源框架?  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  油猴 教程,油猴搜脚本为什么会网页无法显示?  网站建设设计制作营销公司南阳,如何策划设计和建设网站?  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  如何在IIS中配置站点IP、端口及主机头?  如何优化Golang Web性能_Golang HTTP服务器性能提升方法  家庭服务器如何搭建个人网站? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。