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

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

(0)

相关推荐

  • iOS中 UIActionSheet字体的修改

    一,效果图. 二,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController : UIViewController <UIActionSheetDelegate> @end RootViewController.m -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UIActionSheet *actio

  • iOS实现自定义起始时间选择器视图

    随着界面的整体效果的各种展现, 起始时间选择器的展现也需求突出! 最近项目中发现时间选择器使用处还挺多, 数了数原型图发现有6处. 便决定自定义时间选择器视图写个 Demo, 封装好在所需控制器里直接调用! 主要功能: 调起时间选择器, 传值(起始时间/截止时间), 两者时间均要合理, 不能超过未来时间, 并且起始时间不能大于截止时间. 点击取消或空白处收起时间选择器. 如果需要可以根据自己的需求来修改界面, 效果如下: 主要步骤: 创建时间选择器Picker 且确认取消按钮实现功能逻辑 创建展

  • IOS 获取网络图片大小实例详解

    IOS 获取网络图片大小实例详解 在iOS开发过程中经常需要通过网络请求加载图片,有时,需要在创建UIImageView或UIButton来显示图片之前需要提前知道图片的尺寸,根据图片尺寸创建对应大小的控件.但是对于网络图片来说,要想通过最优的方法获得尺寸就略微有点困难,大体思路就是下面这种: 如果有使用SDWebImage,则首先检查是否缓存过该图片,如果没有,先通过文件头获取图片大小(针对格式为png.gif.jpg文件获取其尺寸大小),如果获取失败,则下载完整的图片data,然后计算大小,

  • IOS打开照相机与本地相册选择图片实例详解

    IOS打开照相机与本地相册选择图片 最近正好项目里面要集成"打开照相机与本地相册选择图片"的功能,今天就在这边给大家写一个演示程序:打开相机拍摄后或者在相册中选择一张照片,然后将它显示在界面上.好了废话不多说,因为比较简单直接上源码. 首先,我们在头文件中添加需要用到的actionSheet控件,显示图片的UIImageView控件,并且加上所需要的协议 #import <UIKit/UIKit.h> @interface ImagePickerViewController

  • IOS中UIWebView、WKWebView之JS交互

    做客户端开发,肯定避免不了JS交互,于是自己对苹果接口做了个简易封装: JSExport-->UIWebView+Interaction.WKScriptMessageHandler -->WKWebView+Interaction以备以后使用. 代码非常简洁,见这里:https://github.com/V5zhou/JSInteraction.git 旧方式 旧的交互方式有通过UIWebViewDelegate实现的:JS与客户端定义好跳转页面参数,在将要跳转时捕获关键字,然后处理业务.

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

    iOS实现粒子发射动画效果图 代码已上传 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo 动画效果用 CAEmitterLayer 实现.CAEmitterLayer 显示粒子发射动画,具体的粒子由 CAEmitterCell 封装.代码示例是展示 CAEmitterLayer 如何使用.为了方便,直接在控制器(UIViewController)中设置 CAEmitterLayer.如果在项目中使用,有时在自定义视图(UIVi

  • iOS使用xib手动实现动画效果的方法

    今天在做项目的时候,项目使用的是xib做的,页面中需要有个动画效果,使用UIView动画如下图: 想要改变视图的宽度来实现动画效果,将这条约束拖到ViewController成为属性 使用如下方法,发现不能进行动画效果: 但是发现没有相关的动画效果.最后发现使用xib动画和普通的动画不太一样,需要如下操作才能成功实现动画: 两个重要的注意事项: 您需要调用 layoutIfNeeded 动画块内.苹果公司其实建议你称之为一次之前要确保所有挂起的布局操作已完成的动画块 您需要调用它专门在父视图上

  • JS实现的小火箭发射动画效果示例

    本文实例讲述了JS实现的小火箭发射动画效果.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>小火箭发射</title> <style type="text/css"> *{ margin: 0px; padding: 0px; } .big

  • Android实现仿iOS菊花加载圈动画效果

    常见的实现方式 切图,做旋转动画 自定义View,绘制效果 gif图 1.切图会增加体积,但相对简单,不过在换肤的场景下,会使用不同颜色,需要准备多张图,不够灵活. 2.由于自定义的好处,不同颜色只需要提供自定义属性,换肤时切换属性设置即可,比较灵活. 3.gif图普遍比较大,而且加载gif没有原生支持,需要引入第三方库,而且消耗内存比较大,不推荐. 效果图: 完整代码 自定义属性: <?xml version="1.0" encoding="utf-8"?&

  • 利用Matlab复刻两款粒子爱心动画效果

    目录 粒子爱心1 效果图 粒子爱心2 效果图 粒子爱心1 function particleHeart1 % @author : slandarer % 调整背景及比例 ax=gca;hold on ax.DataAspectRatio=[1,1,1]; ax.XLim=[-25,25]; ax.YLim=[-25,20]; ax.Color=[0,0,0]; ax.XColor='none'; ax.YColor='none'; set(gcf,'Color',[0,0,0]); % 散点位置

  • WPF实现文字粒子闪烁动画效果

    本文实例为大家分享了WPF实现文字粒子闪烁动画的具体代码,供大家参考,具体内容如下 实现效果如下: 思路:首先根据显示文本创建文本路径Geometry,然后在路径内随机生成圆形粒子并添加动画. 步骤: 1.粒子类Particle.cs public class Particle { /// <summary> /// 形状 /// </summary> public Ellipse Shape; /// <summary> /// 坐标 /// </summary

  • iOS实现抖音点赞动画效果

    本文实例为大家分享了iOS实现抖音点赞动画的具体代码,供大家参考,具体内容如下 1. 概述 最近看到抖音点赞爱心的动画效果比较好,出于好奇,自己也研究仿照动画效果写了一个,不喜欢的朋友可不要喷我噢!!! 话不多说,先来看一下执行效果. 2. 动画分析 上面的示例效果有点快,现在来看一个慢的,然后在分析动画组成. 这回看清楚了吧,哈哈. 2.1 动画过程分析 咱们就以10秒的点赞动画来分析一下: 点赞的时候: 1.点击的时候,白色爱心逐渐变小到一定程度,然后变成红色爱心.(3秒) 2.红色爱心慢慢

  • IOS框架Spring常用的动画效果

    Spring 作用:开发中常用的动画效果及自定义转场动画 演示 介绍 SpringView 最重要的一个类,是一个继承自UIView的控件,所有的动画属性,都是围绕着这个类的对象 demo跑起来有一个code按钮,点击这个按钮会出现已经设置的动画属性及其api,自己可以自定义设置,其对应的api这里就不赘述了(上面的gif图片也可以看到) demo里code按钮点开显示的layer对象是用SpringView创建的对象,不是我们平时说的layer animateNext(completion:

  • 详解 iOS 系统中的视图动画

    动画为用户界面的状态转换提供了流畅的可视化效果, 在 iOS 中大量使用了动画效果, 包括改变视图位置. 大小. 从可视化树中删除视图, 隐藏视图等. 你可以考虑用动画效果给用户提供反馈或者用来实现有趣的特效. 在 iOS 系统中, Core Animation 提供了内置的动画支持, 创建动画不需要任何绘图的代码, 你要做的只是激发指定的动画, 接下来就交给 Core Animation 来渲染, 总之, 复杂的动画只需要几行代码就可以了. 哪些属性可以添加动画效果 根据 iOS 视图编程指南

  • iOS中利用CAEmitterLayer实现粒子动画详解

    前言 你肯定见过很酷炫的iOS动画吧,例如微信的表情雨

随机推荐