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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。