美文网首页iOS开发iOS开发资料收集区ios
使用粒子动画,让你的APP下点儿雪

使用粒子动画,让你的APP下点儿雪

作者: 庸者的救赎 | 来源:发表于2016-11-01 17:35 被阅读1923次
    又是一年

    废话

    最近气温骤降,分分钟感觉要下雪的样子,一想到雪,就想到过年了,一想到过年我就...

    然而都过年了,我还没挣到钱...

    算了,还是想想雪吧…

    如果能使用代码,让自己的App下点儿雪,想想都cool到没朋友了

    唉,不废话了,先看看效果

    效果

    具体实现

    代码实现方面其实没有啥技巧,咱们就直接上

    要实现粒子动画需要使用一个叫CAEmitterLayer的类,这个东西在QuartzCore框架里面,是一个直接作用与layer层的框架

    相关代码:

    class SnowView: UIView {
    
        override init(frame: CGRect) {
            super.init(frame: frame) 
            
            let emitter = self.layer as! CAEmitterLayer // 修改view的layer
            emitter.emitterPosition = CGPoint(x: bounds.size.width/2, y: 0) // 发射粒子的位置
            emitter.emitterSize = bounds.size // 范围
            emitter.emitterShape = kCAEmitterLayerRectangle // 粒子形状
            
            let emitterCell = CAEmitterCell() // 创建粒子
            emitterCell.contents = UIImage(named: "flake")!.cgImage // 载入粒子图片
            emitterCell.birthRate = 200 // 每秒释放多少个粒子
            emitterCell.lifetime = 3.5 // 每个粒子的生命周期
            emitterCell.color = UIColor.white.cgColor // 粒子的颜色
            emitterCell.redRange = 0.0 // RGBA设置
            emitterCell.blueRange = 0.1
            emitterCell.greenRange = 0.0
            emitterCell.alphaRange = 0.5
            emitterCell.velocity = 9.8 // 重力加速度也就是物理里面G
            emitterCell.velocityRange = 350 // 加速范围
            emitterCell.emissionRange = CGFloat(M_PI_2) // 下落是旋转的角度
            emitterCell.emissionLongitude = CGFloat(-M_PI) //
            emitterCell.yAcceleration = 70 // 发射速度
            emitterCell.xAcceleration = 0  
            emitterCell.scale = 0.33 
            emitterCell.scaleRange = 1.25
            emitterCell.scaleSpeed = -0.25
            emitterCell.alphaRange = 0.5
            emitterCell.alphaSpeed = -0.15
            
            emitter.emitterCells = [emitterCell] // 载入
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override class var layerClass: AnyClass {
            return CAEmitterLayer.self
        }
    }
    

    上面这段代码,是雪花粒子动画的完整实现,注释写的很清楚,这里需要注意的就是后面这几句

    override class var layerClass: AnyClass {
        return CAEmitterLayer.self
    }
    

    这里一定要重载layer属性,不然开头第一句的强转会崩溃,你懂的

    let emitter = self.layer as! CAEmitterLayer
    

    行了,下雪了...

    根据需求改变

    可如果代码就这么实现,就安心了,太不符合程序员的逼格了

    在实际的开发中可能会遇到各种问题:

    比如产品经理说:我要做到想在哪里下雪就在那里下雪...

    WTF!!!

    产品经理就是这么任性

    怎么办?

    通常的处理方法有以下几种:

    • 子类化
    • 写到分类/扩展里面

    如果你能想到子类化,说明你是有面向对象思想的(当然有没有对象就不知道了😜)

    如果你能想写到分类里面,说明你对iOS编程已经有些入门了

    但是我想说,以上两种方法都是最佳的解决办法.

    为啥不用继承,请出门左转看看这篇文章

    为啥不写成分类/扩展,请出门右转...

    嗯?那个同学你回来,这个不需要出门右转,直接跟你说为啥

    其实,写到分类/扩展里面是个不错的选择,但是随着开发的进行,你会发现分类/扩展里面的东西会越来越多,慢慢的成了一个大熔炉,啥东西都放在里面,最后成了一个垃圾桶,难以维护,甚至到最后你自己都找不到自己之前写的东西在哪里,再最后,你连自己是否写过这个方法都不知道了...

    这里最佳的实现方法是,使用面向协议的方法解决这个问题,这样不但清晰,而且更swift

    面向协议

    至于啥是面向协议,请看下图

    百度和Google在向你招手

    行了,直接上代码

    import Foundation
    import UIKit
    import QuartzCore
    
    protocol Snow {}
    
    extension Snow where Self: UIView {
        
        func createSnow() {
            let emitter = layer as! CAEmitterLayer
            emitter.emitterPosition = CGPoint(x: bounds.size.width / 2, y: 0)
            emitter.emitterSize = bounds.size
            emitter.emitterShape = kCAEmitterLayerRectangle
            
            let emitterCell = CAEmitterCell()
            emitterCell.contents = UIImage(named: "flake.png")!.cgImage
            emitterCell.birthRate = 200
            emitterCell.lifetime = 3.5
            emitterCell.color = UIColor.white.cgColor
            emitterCell.redRange = 0.0
            emitterCell.blueRange = 0.1
            emitterCell.greenRange = 0.0
            emitterCell.velocity = 10
            emitterCell.velocityRange = 350
            emitterCell.emissionRange = CGFloat(M_PI_2)
            emitterCell.emissionLongitude = CGFloat(-M_PI)
            emitterCell.yAcceleration = 70
            emitterCell.xAcceleration = 0
            emitterCell.scale = 0.33
            emitterCell.scaleRange = 1.25
            emitterCell.scaleSpeed = -0.25
            emitterCell.alphaRange = 0.5
            emitterCell.alphaSpeed = -0.15
            
            emitter.emitterCells = [emitterCell]
        }
    }
    

    这样以后,你的view代码就变成下面这样简单明了

    import UIKit
    
    class SnowView: UIView, Snow {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            createSnow()
        }
        
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override class var layerClass: AnyClass {
            return CAEmitterLayer.self
        }
    }
    

    以后产品经理想在那里下雪,你就让那个view遵循Snow协议,然后调用creatSnow(),就行了,自豪的告诉产品,他的理想已经实现

    呃...

    是不是跑题了?咱们不是在聊如何下雪么 ?怎么跑面向协议编程上去了?

    行吧,不管如何,已经可以愉快的下雪了,真的快过年了...

    项目源码奉上

    然而,还没有挣到钱...

    生命不息,折腾不止...
    I'm not a real coder, but i love it so much!

    相关文章

      网友评论

      本文标题:使用粒子动画,让你的APP下点儿雪

      本文链接:https://www.haomeiwen.com/subject/vsimuttx.html