想必以前QQ空間的點(diǎn)贊效果大家都知道吧,點(diǎn)贊之后按鈕周圍會有一圈爆裂的小圓點(diǎn);還有微信的紅包雨表情動畫等,以及煙花,火焰效果。這些看似很炫酷的動畫可能讓我們敬而遠(yuǎn)之,但是其實(shí)iOS封裝的很好,利用簡單的幾行代碼就能完成很炫酷的動畫效果。由于目前正在玩兒iOS動畫的內(nèi)容,利用iOS的CAEmitterLayer結(jié)合CAEmitterCell能夠達(dá)這些效果。不BB了,先上幾個效果圖。代碼已傳githubEmitterAnimation。


馬丹 有沒有辦法一次性放很多個gif呀。。。。。。。
CAEmitterLayer與CAEmitterCell
CAEmitterLayer是CALayer的一個常用子類,CALayer的子類有很多,如果能很好的使用它們會得到一些意想不到的效果。CAEmitterLayer就是其中之一,CAEmitterLayer是用于實(shí)現(xiàn)基于Core Animation的粒子發(fā)生器系統(tǒng)。

所謂粒子,就是很多小顆粒,當(dāng)讓QQ空間的點(diǎn)贊動畫的粒子也可以不用CAEmitterLayer粒子發(fā)生器來實(shí)現(xiàn),不過這樣會麻煩很多。在粒子系統(tǒng)中,CAEmitterLayer是用來發(fā)射粒子的,他所發(fā)射的粒子就是CAEmitterCell(當(dāng)然粒子也可以發(fā)射粒子,也就是CAEmitterCell也可以發(fā)射CAEmitterCell)。可以認(rèn)為CAEmitterLayer是CAEmitterCell的工廠,通過不同的設(shè)置就會不斷的產(chǎn)生想要的粒子。
原理其實(shí)很簡單,但是動畫就是這樣,需要花時間去理解屬性,只有很好的用它的屬性,才能達(dá)到很炫酷的效果。查看API會發(fā)現(xiàn)CAEmitterLayer和CAEmitterCell的屬性都是很多的,并且有很多相同的屬性。在CAEmitterLayer中,一些屬性決定了粒子從什么樣的幾何特性上發(fā)射出來,這個幾何特性包括了位置,形狀,大小,并且還有一些渲染屬性,用于一些渲染的效果。另外一些屬性CAEmitterLayer和CAEmitterCell都有的,在這里可能會迷糊,但是API說明的很清楚,CAEmitterLayer的這些屬性會作為CAEmitterCell相同屬性的系數(shù),舉個??,如果CAEmitterCell的birthRate = 10(每秒產(chǎn)生的粒子數(shù)量),其所屬的CAEmitterLayer的birthRate = 2,那么在其他參數(shù)默認(rèn)的情況下,這個CAEmitterCell總的每秒產(chǎn)生的粒子數(shù)量是10 * 2 = 20 。也就是每秒會產(chǎn)生20個這樣的粒子。
另外,會發(fā)現(xiàn)CAEmitterCell的很多屬性都帶有一個Range,比如scaleRange、velocityRange,這些決定粒子自身的一些特性的屬性大多都是以“中間值” + 范圍(Range)的方式表示的。再舉個??,比如scale = 0.5(縮放值)和scaleRange = 0.2(縮放的范圍),那么表示的實(shí)際CAEmitterCell的縮放就是scale±scaleRange,即0.3~0.7這個范圍。
紅包雨demo
初步了解了這些之后,我們就可以跟著代碼來實(shí)現(xiàn)實(shí)現(xiàn)一個紅包雨的功能。實(shí)現(xiàn)起來很簡單,只要設(shè)置好屬性就行了,這些屬性的詳細(xì)含義會在下面的篇幅仔細(xì)講解,先來試下一個小demo。就是最開始的第個效果圖。
實(shí)現(xiàn)步驟
- 設(shè)置
CAEmitterLayer以及它的一些模式,并添加到要顯示的view的圖層上,當(dāng)然也可以替換view的圖層 - 給這個
CAEmitterLayer配置CAEmitterCell。 - 沒有第三步了。
- 設(shè)置
CAEmitterLayer以及它的一些模式,并添加到要顯示的view的圖層上,當(dāng)然也可以替換view的圖層。這里是直接添加到控制器的view的layer上的,這個view的layer是一個calyer類型的,如果想替換掉calyer,可以自定義view,并在view里面重寫如下方法即可實(shí)現(xiàn)替換
// 替換view的layer
+ (Class)layerClass{return [CAEmitterLayer class];}
這里并沒有替換,而是直接添加。當(dāng)然為了后面方便這里把CAEmitterLayer設(shè)置為屬性。詳細(xì)代碼如下,可以看注釋
@interface ViewController ()
@property (nonatomic, strong) CAEmitterLayer * redpacketLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self redpacketRain];
}
/**
* 紅包雨
*/
- (void)redpacketRain{
// 1. 設(shè)置CAEmitterLayer
CAEmitterLayer * redpacketLayer = [CAEmitterLayer layer];
[self.view.layer addSublayer:redpacketLayer];
self.redpacketLayer = redpacketLayer;
redpacketLayer.emitterShape = kCAEmitterLayerLine; // 發(fā)射源的形狀 是枚舉類型
redpacketLayer.emitterMode = kCAEmitterLayerSurface; // 發(fā)射模式 枚舉類型
redpacketLayer.emitterSize = self.view.frame.size; // 發(fā)射源的size 決定了發(fā)射源的大小
redpacketLayer.emitterPosition = CGPointMake(self.view.bounds.size.width * 0.5, -10); // 發(fā)射源的位置
redpacketLayer.birthRate = 0.f; // 每秒產(chǎn)生的粒子數(shù)量的系數(shù)
}
到這里CAEmitterLayer的就設(shè)置完了,需要注意的是發(fā)射源的emitterPosition這個屬性,是將它放在了頂部,實(shí)現(xiàn)從天上掉下來的效果。
- 給這個
CAEmitterLayer配置CAEmitterCell。在redpacketRain方法里面添加如下代碼。值得注意的是,粒子的內(nèi)容contents是一個CGImageRef類型的,用UIImage需要轉(zhuǎn)換為CGImage.
// 2. 配置cell
CAEmitterCell * snowCell = [CAEmitterCell emitterCell];
snowCell.contents = (id)[[UIImage imageNamed:@"red_paceket"] CGImage]; // 粒子的內(nèi)容 是CGImageRef類型的
snowCell.birthRate = 10.f; // 每秒產(chǎn)生的粒子數(shù)量
snowCell.lifetime = 20.f; // 粒子的生命周期
snowCell.velocity = 8.f; // 粒子的速度
snowCell.yAcceleration = 1000.f; // 粒子再y方向的加速的
snowCell.scale = 0.5; // 粒子的縮放比例
redpacketLayer.emitterCells = @[snowCell]; // 粒子添加到CAEmitterLayer上
- 再添加一個按鈕,通過用KVC設(shè)置
CAEmitterLayer的birthRate來實(shí)現(xiàn)動畫的開始和結(jié)束。
- (IBAction)redpacketClick:(id)sender {
[self.redpacketLayer setValue:@1.f forKeyPath:@"birthRate"];
[self performSelector:@selector(endRedpacketAnimation) withObject:nil afterDelay:2.f];
}
- (void)endRedpacketAnimation{
[self.redpacketLayer setValue:@0.f forKeyPath:@"birthRate"];
}
- run之后點(diǎn)擊按鈕就會出現(xiàn)上圖的效果了。
CAEmitterLayer與CAEmitterCell的屬性詳解
實(shí)現(xiàn)上面的小demo是不是很簡單?不到20行代碼而已,用到的屬性和也很少。那么下雨下雪的效果也是這樣實(shí)現(xiàn)的,只不過是修改屬性值。但是這些效果不夠炫酷,要實(shí)現(xiàn)炫酷的效果得先了解各個屬性的含義,那么接下來花大量的篇幅講解CAEmitterLayer與CAEmitterCell的屬性。
CAEmitterLayer常用屬性
@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 用來裝粒子的數(shù)組
@property float birthRate; // 粒子產(chǎn)生系數(shù),默認(rèn)1.0
@property float lifetime; // 粒子的生命周期系數(shù), 默認(rèn)1.0
@property CGPoint emitterPosition; // 決定了粒子發(fā)射形狀的中心點(diǎn)
@property CGFloat emitterZPosition;
@property CGSize emitterSize; // 發(fā)射源的尺寸大小
@property CGFloat emitterDepth;
@property(copy) NSString *emitterShape; // 發(fā)射源的形狀
@property(copy) NSString *emitterMode; // 發(fā)射模式
@property(copy) NSString *renderMode; // 渲染模式
@property BOOL preservesDepth;
@property float velocity; // 粒子速度系數(shù), 默認(rèn)1.0
@property float scale; // 粒子的縮放比例系數(shù), 默認(rèn)1.0
@property float spin; // 粒子的自旋轉(zhuǎn)速度系數(shù), 默認(rèn)1.0
@property unsigned int seed; // 隨機(jī)數(shù)發(fā)生器
CAEmitterLayer里面的API里面的所有屬性都已經(jīng)貼出來并作了說明,看看注釋并調(diào)試一下就能理解大部分,接下來重點(diǎn)說說一些常用的屬性
1. CAEmitterLayer控制粒子發(fā)射位置和形狀的屬性
CAEmitterLayer發(fā)射的粒子并不是雜亂無章的,我們可以設(shè)置它發(fā)射粒子時的位置、幾何圖形等。通過以下屬性去配置:
-
emitterPosition:決定發(fā)射源的中心點(diǎn),如果比如上面的demo中設(shè)置的為CGPointMake(self.view.bounds.size.width * 0.5, -10),那么x軸方向上就是在view的中心點(diǎn),然后再設(shè)置emitterSize = CGSizeMake(40, 0);的話,那么就是self.view.bounds.size.width * 0.5的左右兩邊各20。API中還提供了一個emitterZPosition,這個是用在三維坐標(biāo)中的,筆者暫時對三維的沒有研究。 -
emitterSize: 決定發(fā)射源的大小 -
emitterShape:表示粒子從什么形狀發(fā)射出來,它并不是表示粒子自己的形狀。是一個枚舉類型,提供如下類型可供選擇:
kCAEmitterLayerPoint
kCAEmitterLayerLine
kCAEmitterLayerRectangle
kCAEmitterLayerCuboid
kCAEmitterLayerCircle
kCAEmitterLayerSphere
-
kCAEmitterLayerPoint:點(diǎn)形狀,發(fā)射源的形狀就是一個點(diǎn),位置在上面position設(shè)置的位置 -
kCAEmitterLayerLine:線形狀,發(fā)射源的形狀是一條線,位置在rect的橫向的位于垂直方向中間那條 -
kCAEmitterLayerRectangle:矩形狀,發(fā)射源的形狀是一個矩形,就是上面生成的那個矩形rect -
kCAEmitterLayerCuboid:立體矩形形狀(3D),發(fā)射源是一個立體矩形,這里要生效的話需要設(shè)置z方向的數(shù)據(jù),如果不設(shè)置就同矩形狀 -
kCAEmitterLayerCircle:圓形形狀,發(fā)射源是一個圓形,形狀為矩形包裹的那個圓,二維的 -
kCAEmitterLayerSphere:立體圓形(3D),三維的圓形,同樣需要設(shè)置z方向數(shù)據(jù),不設(shè)置則通二維一樣
這些形狀可以在調(diào)試的時候修改來看看有什么不同,比如我們設(shè)置的紅包效果,就是用的kCAEmitterLayerLine,結(jié)合了emitterSize來是實(shí)現(xiàn)從頂部掉下來的效果,而emitterSize的height其實(shí)是被忽略的。接下來我們看如下代碼的效果圖解:
redpacketLayer.emitterPosition = CGPointMake(100, 100);
redpacketLayer.emitterSize = CGSizeMake(20, 0);
redpacketLayer.emitterShape = kCAEmitterLayerLine;

emitterShape的幾種模式其實(shí)很好理解,以emitterPosition的點(diǎn)為中心,然后作一個對應(yīng)的形狀,如直線、圓形、矩形,在這個形狀上產(chǎn)生相應(yīng)的粒子。
-
emitterMode:發(fā)射模式,這個字段規(guī)定了在特定形狀上發(fā)射的具體形式是什么。它的作用其實(shí)就是進(jìn)一步?jīng)Q定發(fā)射的區(qū)域是在發(fā)射形狀的哪一部份。
kCAEmitterLayerPoints
kCAEmitterLayerOutline
kCAEmitterLayerSurface
kCAEmitterLayerVolume
-
kCAEmitterLayerPoints:點(diǎn)模式,發(fā)射器是以點(diǎn)的形式發(fā)射粒子。發(fā)射點(diǎn)就是形狀的某個特殊的點(diǎn),比如shap是一個點(diǎn)的話,那么這個點(diǎn)就是中心點(diǎn),如果是圓形,那么就是圓心。 -
kCAEmitterLayerOutline:輪廓模式,從形狀的邊界上發(fā)射粒子。 -
kCAEmitterLayerSurface:表面模式,從形狀的表面上發(fā)射粒子。 -
kCAEmitterLayerVolume:是相對于3D形狀的“球體內(nèi)”或“立方體內(nèi)”發(fā)射,筆者暫時也不是很了解3D的。
2. CAEmitterLayer決定粒子系數(shù)的屬性
-
birthRate: 粒子產(chǎn)生系數(shù),默認(rèn)1.0;每個粒子cell的產(chǎn)生率乘以這個粒子產(chǎn)生系數(shù),得出每一秒產(chǎn)生這個粒子的個數(shù)。 即:每秒粒子產(chǎn)生個數(shù) = layer.birthRate * cell.birthRate ; -
lifetime:粒子的生命周期系數(shù),默認(rèn)1.0。計算方式同上; -
velocity:粒子速度系數(shù), 默認(rèn)1.0。計算方式同上; -
scale:粒子的縮放比例系數(shù), 默認(rèn)1.0。計算方式同上; -
spin:自旋轉(zhuǎn)速度系數(shù), 默認(rèn)1.0。計算方式同上;
3.CAEmitterLayer決定粒子內(nèi)容的屬性
-
emitterCells:用來裝粒子的數(shù)組。每種粒子就是一個CAEmitterCell。在API中可以看到CAEmitterCell是服從CAMediatiming協(xié)議的,可以通過beginTime來控制subCell的出現(xiàn)時機(jī)。
CAEmitterCell常用屬性
@property(nullable, copy) NSString *name; // 粒子名字, 默認(rèn)為nil
@property(getter=isEnabled) BOOL enabled;
@property float birthRate; // 粒子的產(chǎn)生率,默認(rèn)0
@property float lifetime; // 粒子的生命周期,以秒為單位。默認(rèn)0
@property float lifetimeRange; // 粒子的生命周期的范圍,以秒為單位。默認(rèn)0
@property CGFloat emissionLatitude;// 指定緯度,緯度角代表了在x-z軸平面坐標(biāo)系中與x軸之間的夾角,默認(rèn)0:
@property CGFloat emissionLongitude; // 指定經(jīng)度,經(jīng)度角代表了在x-y軸平面坐標(biāo)系中與x軸之間的夾角,默認(rèn)0:
@property CGFloat emissionRange; //發(fā)射角度范圍,默認(rèn)0,以錐形分布開的發(fā)射角度。角度用弧度制。粒子均勻分布在這個錐形范圍內(nèi);
@property CGFloat velocity; // 速度和速度范圍,兩者默認(rèn)0
@property CGFloat velocityRange;
@property CGFloat xAcceleration; // x,y,z方向上的加速度分量,三者默認(rèn)都是0
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;
@property CGFloat scale; // 縮放比例, 默認(rèn)是1
@property CGFloat scaleRange; // 縮放比例范圍,默認(rèn)是0
@property CGFloat scaleSpeed; // 在生命周期內(nèi)的縮放速度,默認(rèn)是0
@property CGFloat spin; // 粒子的平均旋轉(zhuǎn)速度,默認(rèn)是0
@property CGFloat spinRange; // 自旋轉(zhuǎn)角度范圍,弧度制,默認(rèn)是0
@property(nullable) CGColorRef color; // 粒子的顏色,默認(rèn)白色
@property float redRange; // 粒子顏色red,green,blue,alpha能改變的范圍,默認(rèn)0
@property float greenRange;
@property float blueRange;
@property float alphaRange;
@property float redSpeed; // 粒子顏色red,green,blue,alpha在生命周期內(nèi)的改變速度,默認(rèn)都是0
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
@property(nullable, strong) id contents; // 粒子的內(nèi)容,為CGImageRef的對象
@property CGRect contentsRect;
@property CGFloat contentsScale;
@property(copy) NSString *minificationFilter;
@property(copy) NSString *magnificationFilter;
@property float minificationFilterBias;
@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 粒子里面的粒子
@property(nullable, copy) NSDictionary *style;
CAEmitterCell里面的API里面的大部分屬性作了說明,看看注釋并調(diào)試一下就能理解大部分,接下來重點(diǎn)說說一些常用的屬性。CAEmitterLayer就是粒子的工廠,但是要實(shí)現(xiàn)效果就需要CAEmitterCell的幫助。
1.CAEmitterCell決定生命狀態(tài)的屬性
-
lifetime、lifetimeRange:粒子在系統(tǒng)上的生命周期,即存活時間,單位是秒。配合lifetimeRage來讓粒子生命周期均勻變化,以便可以讓粒子的出現(xiàn)和消失顯得更加離散。 -
birthRate:每秒鐘產(chǎn)生的粒子的數(shù)量,是浮點(diǎn)數(shù)。對于這個數(shù)量為浮點(diǎn)數(shù),在測試的時候可以靈活使用它。比如你想看粒子的運(yùn)動狀態(tài),但是太多了可能會很迷糊,這時候你把birthRate = 0.1f,其他參數(shù)不變,就能看到單個粒子的運(yùn)動狀態(tài)。
2.CAEmitterCell決定內(nèi)容的屬性
-
contents:為CGImageRef的對象。關(guān)于contents會聯(lián)想到CALayer了,在CALayer中展示靜態(tài)的圖片是需要用到這個屬性。提供一張圖片,作為粒子系統(tǒng)的粒子。但是因?yàn)榱W酉到y(tǒng)可以給粒子上色,為了做出好的顏色變換效果,通常提供的圖片為純色的圖片,一般為白色。 -
name:粒子的名字。初看沒什么用,但是當(dāng)CAEmitterLayer里面有很多個cell的時候,給每個cell設(shè)置好名字,要修改一些屬性以達(dá)到動畫效果的改變等,就可以通過KVC拿到這個cell的某個屬性。在后面的幾個demo中都用用到。
3.CAEmitterCell決定顏色狀態(tài)的屬性
粒子系統(tǒng)之所以能做出炫酷的效果,和它的色彩多樣化有必不可上的關(guān)系,在
CAEmitterCell中提供了較多的顏色控制屬性這部分屬性讓你獲得了控制粒子顏色,顏色變化范圍和速度的能力,你可以憑借它來完成一些漸變的效果或其它構(gòu)建在它之上的酷炫效果。接下來就看看這些顏色屬性。
-
color:color是粒子的顏色屬性,這個顏色屬性的作用是給粒子上色,它的實(shí)現(xiàn)方法很簡單,就是將contents自身的顏色的RGBA值 *color的RGBA值,就得到最終的粒子的顏色。為了很好的計算,通常用白色的圖片作為contents,因?yàn)樗腞GB都是255,轉(zhuǎn)換為UIColor中的component就是1,用color乘上它就能得到color設(shè)置的顏色效果。 -
redRange、greenRange、blueRange、alphaRange:這些是對應(yīng)的color的RGBA的取值范圍,取值范圍為0~1,比如如下設(shè)置中
snowCell.color = [[UIColor colorWithRed:0.1 green:0.2 blue:0.3 alpha:0.5]CGColor];
snowCell.redRange = 0.1;
snowCell.greenRange = 0.1;
snowCell.blueRange = 0.1;
snowCell.alphaRange = 0.1;
對應(yīng)的RGBA的取值范圍就是:R(00.2)、G(0.10.3)、B(0.20.4)、A(0.40.6)。
-
redSpeed、greenSpeed、blueSpeed、alphaSpeed:這些是對應(yīng)的是粒子的RGBA的變化速度,取值范圍為0~1。表示每秒鐘的RGBA的變化率。這個變化率的計算方式其實(shí)很簡單,先看下面的幾行代碼:
snowCell.lifetime = 20.f; // 粒子的生命周期
snowCell.color = [[UIColor colorWithRed:0.f green:1.f blue:1.f alpha:1.f]CGColor];
snowCell.redSpeed = 0.2;
這里設(shè)置了粒子顏色的RGBA,以及redSpeed,其他的沒設(shè)置默認(rèn)為0。粒子的生命周期(lifetime)為20秒,那么這個粒子從產(chǎn)生到消失的時間就是20秒。它的Red值為0,redSpeed為0.2,那么在粒子的這個生命周期內(nèi),粒子的每秒鐘的Rde值就會增加0.2 * 255,表現(xiàn)在外觀上的狀態(tài)就是粒子顏色在不斷變化,接近白色。最后粒子生命周期結(jié)束的時候,粒子的color正好是RGBA(1,1,1,1)。當(dāng)然個變化的速度也可以負(fù)數(shù),計算方式相同。比如要設(shè)置煙花的效果,那么要讓在爆炸的過程中顏色變化,就是通過這樣的設(shè)置達(dá)到的效果。
4.CAEmitterCell決定飛行軌跡的屬性。
CAEmitterLayer雖然控制了粒子的發(fā)射位置和形狀等,但是粒子的飛行同時也需要自身去決定,比如粒子發(fā)射的角度、發(fā)散的范圍,自轉(zhuǎn)屬性等。那么接下來就說說這些屬性。
-
emissionLongitude: 指定經(jīng)度,經(jīng)度角代表了在x-y軸平面坐標(biāo)系中與x軸之間的夾角,默認(rèn)0,弧度制。順時針方向?yàn)檎?。這樣解釋看起來不好懂,畫個圖就明白了。
emissionLatitude
粒子沿著X軸向右飛行,如果emissionLongtitude = 0那么粒子會沿著X軸向右飛行,如果想沿著Y軸向下飛行,那么可以設(shè)置emissionLongtitude = M_PI_2。 -
emissionLatitude:這個和emissionLongitude的原理是一樣的,只不過是在三維平面上的x-z軸上與x軸的夾角。 -
emissionRange:發(fā)射角度范圍,默認(rèn)0,以錐形分布開的發(fā)射角度。角度用弧度制。粒子均勻分布在這個錐形范圍內(nèi)。在二維平面中,若想要以錐形的形式發(fā)射粒子,然粒子的發(fā)散范圍不是一條線,而是一個錐形區(qū)域(也可以叫做扇形),那么可以通過emissionRange來設(shè)置一個范圍。比如想沿Y軸向下成90度的錐形區(qū)域發(fā)散,那么可以通過如下代碼設(shè)置:
snowCell.emissionLongitude = M_PI_2;
snowCell.emissionRange = M_PI_4;
實(shí)現(xiàn)的效果如下:

可以看到粒子是沿著Y軸向下成90度的一個發(fā)散角度。如果想實(shí)現(xiàn)火焰等效果。就可以這樣,把角度調(diào)小一點(diǎn)即可。
-
velocity、velocityRange、xAcceleration、yAcceleration、zAcceleration:前面兩個是粒子的初速度和初速度的范圍,后面是三個分別是在x、y、z軸方向的加速度,這個很好理解,初中就應(yīng)該知道加速度的概念,也就是每秒鐘速度的變化量。在放煙花的效果中,煙花飛上天的過程中,模擬一個收重力影響的效果,就可以通過yAcceleration模擬一個重力加速度的效果。 -
spin,spinRange:這兩個屬性很重要,是粒子的自轉(zhuǎn)屬性。在粒子被發(fā)射出去之后,想要實(shí)現(xiàn)自轉(zhuǎn),就需要用到他們。粒子的自轉(zhuǎn)是以弧度制來計算的,表示每秒鐘粒子自轉(zhuǎn)的弧度數(shù)。spin為正數(shù)代表粒子是順時針旋轉(zhuǎn)的,為負(fù)數(shù)的話就是逆時針選轉(zhuǎn)了。舉個??:粒子的生命周期就是20秒,那么你想讓你的粒子這個生命周期內(nèi)剛好自轉(zhuǎn)12周,若spinRange為0,那么粒子的spin值就應(yīng)該為((PI/180)*360 * 2)/20,就得到了每秒需要轉(zhuǎn)動的弧度數(shù)。
5.CAEmitterCell子粒子的屬性
-
emitterCells:看到CAEmitterCell的這個屬性的時候或許會有些疑惑,不用驚訝,前面說過CAEmitterLayer可以產(chǎn)生cell,通用cell也可以產(chǎn)生cell。那么這個屬性就和CAEmitterLayer中的emitterCells一樣,也是一個數(shù)組。這里有幾個需要注意的地方:- 若給cell設(shè)置了subCell,若想控制subCell的方向,那么得考慮父cell的方向?qū)傩?,也就?code>emissionLongtitude和
emissionLatitude這兩個屬性的情況。 - 不管父粒子cell是從什么樣的形狀上發(fā)射出來的,若要發(fā)射subCell,subCell總是從
kCAEmitterLayerPoint形狀上由父粒子的中心發(fā)射出來的。
- 若給cell設(shè)置了subCell,若想控制subCell的方向,那么得考慮父cell的方向?qū)傩?,也就?code>emissionLongtitude和
造幾個小Demo
理解了
CAEmitterLayer與CAEmitterCell的屬性之后,通過粒子系統(tǒng)實(shí)現(xiàn)一些炫酷的動畫效果就很簡單了。接下來對實(shí)現(xiàn)的幾個小demo效果作個思路分享,歡迎提供更好的方法~。
QQ空間點(diǎn)贊動畫
動畫分析
- 點(diǎn)贊的時候先是把按鈕放大再縮小,這個可以用核心動畫里面的關(guān)鍵幀動畫
CAKeyframeAnimation實(shí)現(xiàn) - 放大后馬上回有一圈的粒子發(fā)射,這就是粒子系統(tǒng)實(shí)現(xiàn)
- 然后從贊到取消贊沒有動畫效果
實(shí)現(xiàn)思路
- 自定義按鈕,重寫
setHighlighted方法去掉高亮狀態(tài)。提供兩張圖片,用于默認(rèn)狀態(tài)和選中狀態(tài)。 - 配置發(fā)射源
CAEmitterLayer和粒子CAEmitterCell。由于CAEmitterLayer的birthRate默認(rèn)為1,CAEmitterCell的birthRate默認(rèn)為0,那么先不設(shè)置這兩個屬性。給cell設(shè)置好name,然后自定義一個動畫開始的方法,在這里面通過KVC設(shè)置CAEmitterCell的birthRate以實(shí)現(xiàn)動畫
/**
* 開始動畫
*/
- (void)startAnimation{
// 用KVC設(shè)置顆粒個數(shù)
[self.explosionLayer setValue:@1000 forKeyPath:@"emitterCells.explosionCell.birthRate"];
// 開始動畫
self.explosionLayer.beginTime = CACurrentMediaTime();
// 延遲停止動畫
[self performSelector:@selector(stopAnimation) withObject:nil afterDelay:0.15];
}
/**
* 動畫結(jié)束
*/
- (void)stopAnimation{
// 用KVC設(shè)置顆粒個數(shù)
[self.explosionLayer setValue:@0 forKeyPath:@"emitterCells.explosionCell.birthRate"];
[self.explosionLayer removeAllAnimations];
}
- 重寫按鈕的
setSelected方法,在里面通過關(guān)鍵幀動畫實(shí)現(xiàn)縮放。
/**
* 選中狀態(tài) 實(shí)現(xiàn)縮放
*/
- (void)setSelected:(BOOL)selected{
[super setSelected:selected];
// 通過關(guān)鍵幀動畫實(shí)現(xiàn)縮放
CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];
animation.keyPath = @"transform.scale";
if (selected) { // 從沒有點(diǎn)擊到點(diǎn)擊狀態(tài) 會有爆炸的動畫效果
animation.values = @[@1.5,@2.0, @0.8, @1.0];
animation.duration = 0.5;
animation.calculationMode = kCAAnimationCubic;
[self.layer addAnimation:animation forKey:nil];
// 讓放大動畫先執(zhí)行完畢 再執(zhí)行爆炸動畫
[self performSelector:@selector(startAnimation) withObject:nil afterDelay:0.25];
}else{ // 從點(diǎn)擊狀態(tài)normal狀態(tài) 無動畫效果 如果點(diǎn)贊之后馬上取消 那么也立馬停止動畫
[self stopAnimation];
}
}
結(jié)語
還有幾個動畫的思路就不啰嗦了,實(shí)現(xiàn)起來都很簡單,關(guān)鍵是要去理解這些屬性的作用。另外動畫做起來即使費(fèi)時間,要自己去理解屬性的作用的話需要花時間調(diào)試對比,其實(shí)用其他方式也可以實(shí)現(xiàn)這樣的效果,但是CAEmitterLayer 基于GPU,做這些效果的時候比較方便。demo已經(jīng)上傳github了,提供了下雨、下雪、紅包雨、五彩小球、愛心、火焰、煙花等效果,值得一說的是,煙花需要三個cell,一個提供發(fā)射的shootCell,一個用于爆炸的explodeCell,還有一個用于火花的sparkCell,這些都是父子關(guān)系,一個cell生命周期完了另外一個再出來。這些可以查看代碼體會,都有注釋~。EmitterAnimation
