在iOS中實(shí)現(xiàn)粒子特效,有對(duì)應(yīng)的的屬性CAEmitterLayer,它是Layer的子類(lèi)突勇,用它來(lái)實(shí)現(xiàn)粒子特效不會(huì)怎么占用資源,從而去影響UI的流程性坷虑。
粒子CAEmitterLayer發(fā)射器的基本屬性
//是否允許在規(guī)定的范圍內(nèi)
@property BOOL masksToBounds;
//發(fā)射器的形狀
//kCAEmitterLayerPoint 點(diǎn)的形狀甲馋,粒子從一個(gè)點(diǎn)發(fā)出
//kCAEmitterLayerLine 線的形狀,粒子從一條線發(fā)出
//kCAEmitterLayerRectangle 矩形形狀迄损,粒子從一個(gè)矩形中發(fā)出
//kCAEmitterLayerCuboid 立方體形狀定躏,會(huì)影響z平面的效果
//kCAEmitterLayerCircle 圓形,粒子會(huì)在圓形范圍發(fā)射
//kCAEmitterLayerSphere 球形
@property(copy) NSString *emitterShape;
//發(fā)射器的發(fā)射模式
//kCAEmitterLayerPoints 從發(fā)射器中發(fā)出
//kCAEmitterLayerOutline 從發(fā)射器邊緣發(fā)出
//kCAEmitterLayerSurface 從發(fā)射器表面發(fā)出
//kCAEmitterLayerVolumen 從發(fā)射器中點(diǎn)發(fā)出
@property(copy) NSString *emitterMode;
// 發(fā)射器的尺寸大小
@property CGSize emitterSize;
//發(fā)射器在xy平面的中心位置
@property CGPoint emitterPosition;
//發(fā)射器在Z平面的位置
@property CGFloat emitterZPosition;
粒子的屬性芹敌,也就是特效痊远,需要用到CAEmitterCell這個(gè)類(lèi)
//類(lèi)方法創(chuàng)建發(fā)射單元
+ (instancetype)emitterCell;
//粒子的創(chuàng)建速率
@property float birthRate;
//粒子的生存時(shí)間
@property float lifetime;
//粒子的生存時(shí)間容差
@property float lifetimeRange;
//粒子在Z軸方向的發(fā)射角度
@property CGFloat emissionLatitude;
//粒子在xy平面的發(fā)射角度
@property CGFloat emissionLongitude;
//粒子發(fā)射角度的容差
@property CGFloat emissionRange;
//粒子的速度
@property CGFloat velocity;
//粒子速度的容差
@property CGFloat velocityRange;
//x,y氏捞,z三個(gè)方向的加速度
@property CGFloat xAcceleration;
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;
//縮放大小碧聪,縮放容差和縮放速度
@property CGFloat scale;
@property CGFloat scaleRange;
@property CGFloat scaleSpeed;
//旋轉(zhuǎn)度與旋轉(zhuǎn)容差
@property CGFloat spin;
@property CGFloat spinRange;
//
@property CGColorRef color;
//粒子在rgb三個(gè)色相上的容差和透明度的容差
@property float redRange;
@property float greenRange;
@property float blueRange;
@property float alphaRange;
//粒子在RGB三個(gè)色相上的變化速度和透明度的變化速度
@property float redSpeed;
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
//渲染粒子,可以設(shè)置為一個(gè)CGImage的對(duì)象
@property(strong) id contents;
//渲染的范圍
@property CGRect contentsRect;
好液茎,接下來(lái)我們看一下他的基本用法逞姿。
//創(chuàng)建出layer
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];//遍歷構(gòu)造器創(chuàng)建
//給定尺寸
emitterLayer.frame = CGRectMake(100, 100, 100, 100);
//顯示邊框
emitterLayer.borderWidth = 1.f;
//發(fā)射點(diǎn)
emitterLayer.emitterPosition = CGPointMake(0, 0);
// emitterLayer.masksToBounds = YES;
//發(fā)射模式
emitterLayer.emitterMode = kCAEmitterLayerSurface;
//發(fā)射形狀
emitterLayer.emitterShape = kCAEmitterLayerLine;
[self.view.layer addSublayer:emitterLayer];
CAEmitterCell *cell = [CAEmitterCell emitterCell];
//粒子產(chǎn)生率
cell.birthRate = 1.f;
//粒子生命周期
cell.lifetime = 120.f;
//速度值
cell.velocity = 10;
//速度值的微調(diào)值
cell.velocityRange = 3.f;
//y軸加速度
cell.yAcceleration = 2.f;
//發(fā)射角度
cell.emissionRange = 0.5 *M_1_PI;
//設(shè)置粒子顏色
// cell.color = [UIColor blueColor].CGColor;
cell.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
//讓CAEmitterCell與CAEmitterLayer產(chǎn)生關(guān)系
emitterLayer.emitterCells = @[cell];
然后運(yùn)行后得到的效果如下:
CAEmitterLayer基本的使用也就這樣辞嗡,但為了避免繁瑣的設(shè)置,我們將CAEmitterLayer封裝成一個(gè)較為通用的父類(lèi)供子類(lèi)使用滞造。
首先創(chuàng)建一個(gè)繼承UIView的視圖CAEmitterLayerView续室,由于此view默認(rèn)創(chuàng)建的隱式layer不是CAEmitterLayer,所以我們需要在CAEmitterLayerView.m中重寫(xiě)layerClass方法断部,返回CAEmitterLayer猎贴。由于CAEmitterLayer含有非常多的屬性要設(shè)置,如果都寫(xiě)在CAEmitterLayerView.h中的話(huà)蝴光,會(huì)顯得非常的繁瑣她渴,所以在這里我們寫(xiě)set和get方法,通過(guò)這個(gè)方法蔑祟,當(dāng)我們需要使用哪個(gè)屬性的時(shí)候趁耗,再在子類(lèi)中進(jìn)行調(diào)用即可。CAEmitterLayerView的代碼如下:
CAEmitterLayerView.h
@interface CAEmitterLayerView : UIView
//模仿setter疆虚,getter方法
- (void)setEmitterLayer:(CAEmitterLayer *)layer;
- (CAEmitterLayer *)emitterLayer;
//顯示出當(dāng)前view
- (void)show;
//隱藏
- (void)hide;
@end
CAEmitterLayerView.m
@interface CAEmitterLayerView() {
CAEmitterLayer *_emitterLayer;
}
@end
@implementation CAEmitterLayerView
+(Class)layerClass {
return [CAEmitterLayer class];
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_emitterLayer = (CAEmitterLayer *)self.layer;
}
return self;
}
- (void)setEmitterLayer:(CAEmitterLayer *)layer {
_emitterLayer = layer;
}
- (CAEmitterLayer *)emitterLayer {
return _emitterLayer;
}
- (void)show {
}
- (void)hide {
}
好了苛败,通過(guò)這種方法,我們?cè)陧?xiàng)目中倘若要設(shè)計(jì)下雨或者下雪等效果時(shí)候径簿,只需要繼承該CAEmitterLayerView罢屈,然后在子類(lèi)中實(shí)現(xiàn)對(duì)應(yīng)的效果即可。
1.下雪效果
首先創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖SnowView篇亭,在.m中的代碼如下
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
//初始化一些參數(shù)
self.emitterLayer.masksToBounds = YES;
self.emitterLayer.emitterShape = kCAEmitterLayerLine;
self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
self.emitterLayer.emitterSize = self.frame.size;
self.emitterLayer.emitterPosition = CGPointMake(self.bounds.size.width / 2.f, -20);
}
- (void)show {
//配置
CAEmitterCell *snowFlake = [CAEmitterCell emitterCell];
snowFlake.birthRate = 1.f;
snowFlake.speed = 10.f;
snowFlake.velocity = 2.f;
snowFlake.velocityRange = 10.f;
snowFlake.yAcceleration = 10.f;
snowFlake.emissionRange = 0.5 * M_PI;
snowFlake.spinRange = 0.25 * M_PI;
snowFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
snowFlake.color = [UIColor redColor].CGColor;
snowFlake.lifetime = 180.f;
snowFlake.scale = 0.5;
snowFlake.scaleRange = 0.3;
//添加動(dòng)畫(huà)
self.emitterLayer.emitterCells = @[snowFlake];
}
下雪模型已搭建好缠捌,然后在我們的控制器中導(dǎo)入SnowView
SnowView *sView = [[SnowView alloc] initWithFrame:CGRectMake(100, 400, 100, 100)];
[self.view addSubview:sView];
[sView show];
效果如下:
2.下雨效果
創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖RainView,在.m中的代碼如下
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.emitterLayer.masksToBounds = YES;
self.emitterLayer.emitterShape = kCAEmitterLayerLine;
self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
self.emitterLayer.emitterSize = self.frame.size;
self.emitterLayer.emitterPosition
= CGPointMake(self.bounds.size.width / 2.f, -20);
}
- (void)show {
CAEmitterCell *rainFlake = [CAEmitterCell emitterCell];
rainFlake.birthRate = 25.f;
rainFlake.speed = 10.f;
rainFlake.velocity = 10.f;
rainFlake.velocityRange = 10.f;
rainFlake.yAcceleration = 1000.f;
rainFlake.contents = (__bridge id _Nullable)([UIImage imageNamed:@"234"].CGImage);
rainFlake.color = [UIColor blackColor].CGColor;
rainFlake.lifetime = 7.f;
rainFlake.scaleRange = 0.f;
rainFlake.scale = 0.2f;
//添加動(dòng)畫(huà)
self.emitterLayer.emitterCells = @[rainFlake];
}
效果如下(圖片可以切長(zhǎng)點(diǎn)译蒂,我在這里沒(méi)改圖片曼月,看著效果并沒(méi)那么好):
3.火焰
創(chuàng)建一個(gè)CAEmitterLayerView的子類(lèi)視圖fireView,在這里設(shè)置了兩個(gè)CAEmitterCell(特效)柔昼,在.m中的代碼如下
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
self.emitterLayer.masksToBounds = YES;
self.emitterLayer.renderMode = kCAEmitterLayerAdditive;
self.emitterLayer.emitterSize = CGSizeMake(self.bounds.size.width - 100, 20);
self.emitterLayer.emitterPosition
= CGPointMake(self.bounds.size.width / 2.f, self.bounds.size.height - 20);
}
- (void)show {
//火焰
CAEmitterCell * fire = [CAEmitterCell emitterCell];
fire.birthRate=800;
fire.lifetime=2.0;
fire.lifetimeRange=1.5;
fire.color=[[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1]CGColor];
fire.contents=(id)[[UIImage imageNamed:@"fire"]CGImage];
fire.velocity=160;
fire.velocityRange=80;
fire.emissionLongitude=M_PI+M_PI_2;
fire.emissionRange=M_PI_2;
fire.scaleSpeed=0.3;
fire.spin=0.2;
//煙霧
CAEmitterCell * smoke = [CAEmitterCell emitterCell];
smoke.birthRate=400;
smoke.lifetime=3.0;
smoke.lifetimeRange=1.5;
smoke.color=[[UIColor colorWithRed:1 green:1 blue:1 alpha:0.05]CGColor];
smoke.contents=(id)[[UIImage imageNamed:@"smoke"]CGImage];
smoke.velocity=250;
smoke.velocityRange=100;
smoke.emissionLongitude=M_PI+M_PI_2;
smoke.emissionRange=M_PI_2;
self.emitterLayer.emitterCells = [NSArray arrayWithObjects:smoke,fire, nil];
}
效果如下: