CAEmitterLayer粒子發射器的神奇效果

STzen發表於2017-12-28

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

紅包雨

點贊效果

馬丹 有沒有辦法一次性放很多個gif呀。。。。。。。


CAEmitterLayerCAEmitterCell

CAEmitterLayerCALayer的一個常用子類,CALayer的子類有很多,如果能很好的使用它們會得到一些意想不到的效果。CAEmitterLayer就是其中之一,CAEmitterLayer是用於實現基於Core Animation的粒子發生器系統。

`CALayer`的常用子類

所謂粒子,就是很多小顆粒,當讓QQ空間的點贊動畫的粒子也可以不用CAEmitterLayer粒子發生器來實現,不過這樣會麻煩很多。在粒子系統中,CAEmitterLayer是用來發射粒子的,他所發射的粒子就是CAEmitterCell(當然粒子也可以發射粒子,也就是CAEmitterCell也可以發射CAEmitterCell)。可以認為CAEmitterLayerCAEmitterCell的工廠,通過不同的設定就會不斷的產生想要的粒子。

原理其實很簡單,但是動畫就是這樣,需要花時間去理解屬性,只有很好的用它的屬性,才能達到很炫酷的效果。檢視API會發現CAEmitterLayerCAEmitterCell的屬性都是很多的,並且有很多相同的屬性。在CAEmitterLayer中,一些屬性決定了粒子從什麼樣的幾何特性上發射出來,這個幾何特性包括了位置,形狀,大小,並且還有一些渲染屬性,用於一些渲染的效果。另外一些屬性CAEmitterLayerCAEmitterCell都有的,在這裡可能會迷糊,但是API說明的很清楚,CAEmitterLayer的這些屬性會作為CAEmitterCell相同屬性的係數,舉個?,如果CAEmitterCellbirthRate = 10(每秒產生的粒子數量),其所屬的CAEmitterLayerbirthRate = 2,那麼在其他引數預設的情況下,這個CAEmitterCell總的每秒產生的粒子數量是10 * 2 = 20 。也就是每秒會產生20個這樣的粒子。

另外,會發現CAEmitterCell的很多屬性都帶有一個Range,比如scaleRangevelocityRange,這些決定粒子自身的一些特性的屬性大多都是以“中間值” + 範圍(Range)的方式表示的。再舉個?,比如scale = 0.5(縮放值)和scaleRange = 0.2(縮放的範圍),那麼表示的實際CAEmitterCell的縮放就是scale±scaleRange,即0.3~0.7這個範圍。

紅包雨demo

初步瞭解了這些之後,我們就可以跟著程式碼來實現實現一個紅包雨的功能。實現起來很簡單,只要設定好屬性就行了,這些屬性的詳細含義會在下面的篇幅仔細講解,先來試下一個小demo。就是最開始的第個效果圖。

實現步驟
  • 設定CAEmitterLayer以及它的一些模式,並新增到要顯示的view的圖層上,當然也可以替換view的圖層
  • 給這個CAEmitterLayer配置CAEmitterCell
  • 沒有第三步了。
  1. 設定CAEmitterLayer以及它的一些模式,並新增到要顯示的view的圖層上,當然也可以替換view的圖層。這裡是直接新增到控制器的viewlayer上的,這個viewlayer是一個calyer型別的,如果想替換掉calyer,可以自定義view,並在view裡面重寫如下方法即可實現替換
// 替換view的layer
+ (Class)layerClass{return [CAEmitterLayer class];}
複製程式碼

這裡並沒有替換,而是直接新增。當然為了後面方便這裡把CAEmitterLayer設定為屬性。詳細程式碼如下,可以看註釋

@interface ViewController ()
@property (nonatomic, strong) CAEmitterLayer * redpacketLayer;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self redpacketRain];
    
}

/**
 * 紅包雨
 */
- (void)redpacketRain{
    
    // 1. 設定CAEmitterLayer
    CAEmitterLayer * redpacketLayer = [CAEmitterLayer layer];
    [self.view.layer addSublayer:redpacketLayer];
    self.redpacketLayer = redpacketLayer;
    
    redpacketLayer.emitterShape = kCAEmitterLayerLine;  // 發射源的形狀 是列舉型別
    redpacketLayer.emitterMode = kCAEmitterLayerSurface; // 發射模式 列舉型別
    redpacketLayer.emitterSize = self.view.frame.size; // 發射源的size 決定了發射源的大小
    redpacketLayer.emitterPosition = CGPointMake(self.view.bounds.size.width * 0.5, -10); // 發射源的位置
    redpacketLayer.birthRate = 0.f; // 每秒產生的粒子數量的係數
}
複製程式碼

到這裡CAEmitterLayer的就設定完了,需要注意的是發射源的emitterPosition這個屬性,是將它放在了頂部,實現從天上掉下來的效果。

  1. 給這個CAEmitterLayer配置CAEmitterCell。在redpacketRain方法裡面新增如下程式碼。值得注意的是,粒子的內容contents是一個CGImageRef型別的,用UIImage需要轉換為CGImage.
    // 2. 配置cell
    CAEmitterCell * snowCell = [CAEmitterCell emitterCell];
    snowCell.contents = (id)[[UIImage imageNamed:@"red_paceket"] CGImage];  // 粒子的內容 是CGImageRef型別的
    
    snowCell.birthRate = 10.f;  // 每秒產生的粒子數量
    snowCell.lifetime = 20.f;  // 粒子的生命週期
    
    snowCell.velocity = 8.f;  // 粒子的速度
    snowCell.yAcceleration = 1000.f; // 粒子再y方向的加速的
    
    snowCell.scale = 0.5;  // 粒子的縮放比例
    
    redpacketLayer.emitterCells = @[snowCell];  // 粒子新增到CAEmitterLayer上

複製程式碼
  1. 再新增一個按鈕,通過用KVC設定CAEmitterLayerbirthRate來實現動畫的開始和結束。
- (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"];
}
複製程式碼
  1. run之後點選按鈕就會出現上圖的效果了。

CAEmitterLayerCAEmitterCell的屬性詳解

實現上面的小demo是不是很簡單?不到20行程式碼而已,用到的屬性和也很少。那麼下雨下雪的效果也是這樣實現的,只不過是修改屬性值。但是這些效果不夠炫酷,要實現炫酷的效果得先了解各個屬性的含義,那麼接下來花大量的篇幅講解CAEmitterLayerCAEmitterCell的屬性。

CAEmitterLayer常用屬性

@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 用來裝粒子的陣列
@property float birthRate; // 粒子產生係數,預設1.0
@property float lifetime; // 粒子的生命週期係數, 預設1.0
@property CGPoint emitterPosition; // 決定了粒子發射形狀的中心點
@property CGFloat emitterZPosition;
@property CGSize emitterSize; // 發射源的尺寸大小
@property CGFloat emitterDepth;
@property(copy) NSString *emitterShape; // 發射源的形狀
@property(copy) NSString *emitterMode; // 發射模式
@property(copy) NSString *renderMode; // 渲染模式
@property BOOL preservesDepth;
@property float velocity; // 粒子速度係數, 預設1.0
@property float scale; // 粒子的縮放比例係數, 預設1.0
@property float spin; // 粒子的自旋轉速度係數, 預設1.0
@property unsigned int seed; // 隨機數發生器
複製程式碼

CAEmitterLayer裡面的API裡面的所有屬性都已經貼出來並作了說明,看看註釋並除錯一下就能理解大部分,接下來重點說說一些常用的屬性

1. CAEmitterLayer控制粒子發射位置和形狀的屬性

CAEmitterLayer發射的粒子並不是雜亂無章的,我們可以設定它發射粒子時的位置、幾何圖形等。通過以下屬性去配置:

  • emitterPosition:決定發射源的中心點,如果比如上面的demo中設定的為CGPointMake(self.view.bounds.size.width * 0.5, -10),那麼x軸方向上就是在view的中心點,然後再設定emitterSize = CGSizeMake(40, 0);的話,那麼就是self.view.bounds.size.width * 0.5的左右兩邊各20。API中還提供了一個emitterZPosition,這個是用在三維座標中的,筆者暫時對三維的沒有研究。
  • emitterSize: 決定發射源的大小
  • emitterShape:表示粒子從什麼形狀發射出來,它並不是表示粒子自己的形狀。是一個列舉型別,提供如下型別可供選擇:
kCAEmitterLayerPoint
kCAEmitterLayerLine
kCAEmitterLayerRectangle
kCAEmitterLayerCuboid
kCAEmitterLayerCircle
kCAEmitterLayerSphere
複製程式碼
  1. kCAEmitterLayerPoint:點形狀,發射源的形狀就是一個點,位置在上面position設定的位置
  2. kCAEmitterLayerLine:線形狀,發射源的形狀是一條線,位置在rect的橫向的位於垂直方向中間那條
  3. kCAEmitterLayerRectangle:矩形狀,發射源的形狀是一個矩形,就是上面生成的那個矩形rect
  4. kCAEmitterLayerCuboid:立體矩形形狀(3D),發射源是一個立體矩形,這裡要生效的話需要設定z方向的資料,如果不設定就同矩形狀
  5. kCAEmitterLayerCircle:圓形形狀,發射源是一個圓形,形狀為矩形包裹的那個圓,二維的
  6. kCAEmitterLayerSphere:立體圓形(3D),三維的圓形,同樣需要設定z方向資料,不設定則通二維一樣

這些形狀可以在除錯的時候修改來看看有什麼不同,比如我們設定的紅包效果,就是用的kCAEmitterLayerLine,結合了emitterSize來是實現從頂部掉下來的效果,而emitterSizeheight其實是被忽略的。接下來我們看如下程式碼的效果圖解:

redpacketLayer.emitterPosition = CGPointMake(100, 100);
redpacketLayer.emitterSize = CGSizeMake(20, 0);
redpacketLayer.emitterShape = kCAEmitterLayerLine;
複製程式碼

達到的效果
emitterShape的幾種模式其實很好理解,以emitterPosition的點為中心,然後作一個對應的形狀,如直線、圓形、矩形,在這個形狀上產生相應的粒子。

  • emitterMode:發射模式,這個欄位規定了在特定形狀上發射的具體形式是什麼。它的作用其實就是進一步決定發射的區域是在發射形狀的哪一部份。
kCAEmitterLayerPoints
kCAEmitterLayerOutline
kCAEmitterLayerSurface
kCAEmitterLayerVolume
複製程式碼
  1. kCAEmitterLayerPoints:點模式,發射器是以點的形式發射粒子。發射點就是形狀的某個特殊的點,比如shap是一個點的話,那麼這個點就是中心點,如果是圓形,那麼就是圓心。
  2. kCAEmitterLayerOutline:輪廓模式,從形狀的邊界上發射粒子。
  3. kCAEmitterLayerSurface:表面模式,從形狀的表面上發射粒子。
  4. kCAEmitterLayerVolume:是相對於3D形狀的“球體內”或“立方體內”發射,筆者暫時也不是很瞭解3D的。
2. CAEmitterLayer決定粒子係數的屬性
  • birthRate: 粒子產生係數,預設1.0;每個粒子cell的產生率乘以這個粒子產生係數,得出每一秒產生這個粒子的個數。 即:每秒粒子產生個數 = layer.birthRate * cell.birthRate ;
  • lifetime:粒子的生命週期係數,預設1.0。計算方式同上;
  • velocity:粒子速度係數, 預設1.0。計算方式同上;
  • scale:粒子的縮放比例係數, 預設1.0。計算方式同上;
  • spin:自旋轉速度係數, 預設1.0。計算方式同上;
3.CAEmitterLayer決定粒子內容的屬性
  • emitterCells:用來裝粒子的陣列。每種粒子就是一個CAEmitterCell。在API中可以看到CAEmitterCell是服從CAMediatiming協議的,可以通過beginTime來控制subCell的出現時機。

CAEmitterCell常用屬性

@property(nullable, copy) NSString *name; // 粒子名字, 預設為nil
@property(getter=isEnabled) BOOL enabled; 
@property float birthRate; // 粒子的產生率,預設0
@property float lifetime; // 粒子的生命週期,以秒為單位。預設0
@property float lifetimeRange; // 粒子的生命週期的範圍,以秒為單位。預設0
@property CGFloat emissionLatitude;// 指定緯度,緯度角代表了在x-z軸平面座標系中與x軸之間的夾角,預設0: 
@property CGFloat emissionLongitude; // 指定經度,經度角代表了在x-y軸平面座標系中與x軸之間的夾角,預設0:
@property CGFloat emissionRange; //發射角度範圍,預設0,以錐形分佈開的發射角度。角度用弧度制。粒子均勻分佈在這個錐形範圍內;
@property CGFloat velocity; // 速度和速度範圍,兩者預設0
@property CGFloat velocityRange;
@property CGFloat xAcceleration; // x,y,z方向上的加速度分量,三者預設都是0
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;
@property CGFloat scale; // 縮放比例, 預設是1
@property CGFloat scaleRange; // 縮放比例範圍,預設是0
@property CGFloat scaleSpeed; // 在生命週期內的縮放速度,預設是0
@property CGFloat spin; // 粒子的平均旋轉速度,預設是0
@property CGFloat spinRange; // 自旋轉角度範圍,弧度制,預設是0
@property(nullable) CGColorRef color; // 粒子的顏色,預設白色
@property float redRange; // 粒子顏色red,green,blue,alpha能改變的範圍,預設0
@property float greenRange;
@property float blueRange;
@property float alphaRange;
@property float redSpeed; // 粒子顏色red,green,blue,alpha在生命週期內的改變速度,預設都是0
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
@property(nullable, strong) id contents; // 粒子的內容,為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裡面的大部分屬性作了說明,看看註釋並除錯一下就能理解大部分,接下來重點說說一些常用的屬性。CAEmitterLayer就是粒子的工廠,但是要實現效果就需要CAEmitterCell的幫助。

1.CAEmitterCell決定生命狀態的屬性
  • lifetimelifetimeRange:粒子在系統上的生命週期,即存活時間,單位是秒。配合lifetimeRage來讓粒子生命週期均勻變化,以便可以讓粒子的出現和消失顯得更加離散。
  • birthRate:每秒鐘產生的粒子的數量,是浮點數。對於這個數量為浮點數,在測試的時候可以靈活使用它。比如你想看粒子的運動狀態,但是太多了可能會很迷糊,這時候你把birthRate = 0.1f,其他引數不變,就能看到單個粒子的運動狀態。
2.CAEmitterCell決定內容的屬性
  • contents:為CGImageRef的物件。關於contents會聯想到CALayer了,在CALayer中展示靜態的圖片是需要用到這個屬性。提供一張圖片,作為粒子系統的粒子。但是因為粒子系統可以給粒子上色,為了做出好的顏色變換效果,通常提供的圖片為純色的圖片,一般為白色。
  • name:粒子的名字。初看沒什麼用,但是當CAEmitterLayer裡面有很多個cell的時候,給每個cell設定好名字,要修改一些屬性以達到動畫效果的改變等,就可以通過KVC拿到這個cell的某個屬性。在後面的幾個demo中都用用到。
3.CAEmitterCell決定顏色狀態的屬性

粒子系統之所以能做出炫酷的效果,和它的色彩多樣化有必不可上的關係,在CAEmitterCell中提供了較多的顏色控制屬性這部分屬性讓你獲得了控制粒子顏色,顏色變化範圍和速度的能力,你可以憑藉它來完成一些漸變的效果或其它構建在它之上的酷炫效果。接下來就看看這些顏色屬性。

  • colorcolor是粒子的顏色屬性,這個顏色屬性的作用是給粒子上色,它的實現方法很簡單,就是將contents自身的顏色的RGBA值 * color的RGBA值,就得到最終的粒子的顏色。為了很好的計算,通常用白色的圖片作為contents,因為它的RGB都是255,轉換為UIColor中的component就是1,用color乘上它就能得到color設定的顏色效果。
  • redRangegreenRangeblueRangealphaRange:這些是對應的color的RGBA的取值範圍,取值範圍為0~1,比如如下設定中
    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;
複製程式碼

對應的RGBA的取值範圍就是:R(0~0.2)、G(0.1~0.3)、B(0.2~0.4)、A(0.4~0.6)。

  • redSpeedgreenSpeedblueSpeedalphaSpeed:這些是對應的是粒子的RGBA的變化速度,取值範圍為0~1。表示每秒鐘的RGBA的變化率。這個變化率的計算方式其實很簡單,先看下面的幾行程式碼:
    snowCell.lifetime = 20.f;  // 粒子的生命週期
    snowCell.color = [[UIColor colorWithRed:0.f green:1.f blue:1.f alpha:1.f]CGColor];
    snowCell.redSpeed = 0.2;

複製程式碼

這裡設定了粒子顏色的RGBA,以及redSpeed,其他的沒設定預設為0。粒子的生命週期(lifetime)為20秒,那麼這個粒子從產生到消失的時間就是20秒。它的Red值為0,redSpeed為0.2,那麼在粒子的這個生命週期內,粒子的每秒鐘的Rde值就會增加0.2 * 255,表現在外觀上的狀態就是粒子顏色在不斷變化,接近白色。最後粒子生命週期結束的時候,粒子的color正好是RGBA(1,1,1,1)。當然個變化的速度也可以負數,計算方式相同。比如要設定煙花的效果,那麼要讓在爆炸的過程中顏色變化,就是通過這樣的設定達到的效果。

4.CAEmitterCell決定飛行軌跡的屬性。

CAEmitterLayer雖然控制了粒子的發射位置和形狀等,但是粒子的飛行同時也需要自身去決定,比如粒子發射的角度、發散的範圍,自轉屬性等。那麼接下來就說說這些屬性。

  • emissionLongitude: 指定經度,經度角代表了在x-y軸平面座標系中與x軸之間的夾角,預設0,弧度制。順時針方向為正。這樣解釋看起來不好懂,畫個圖就明白了。
    emissionLatitude
    粒子沿著X軸向右飛行,如果emissionLongtitude = 0那麼粒子會沿著X軸向右飛行,如果想沿著Y軸向下飛行,那麼可以設定emissionLongtitude = M_PI_2
  • emissionLatitude:這個和emissionLongitude的原理是一樣的,只不過是在三維平面上的x-z軸上與x軸的夾角。
  • emissionRange:發射角度範圍,預設0,以錐形分佈開的發射角度。角度用弧度制。粒子均勻分佈在這個錐形範圍內。在二維平面中,若想要以錐形的形式發射粒子,然粒子的發散範圍不是一條線,而是一個錐形區域(也可以叫做扇形),那麼可以通過emissionRange來設定一個範圍。比如想沿Y軸向下成90度的錐形區域發散,那麼可以通過如下程式碼設定:
    snowCell.emissionLongitude = M_PI_2;
    snowCell.emissionRange = M_PI_4;
複製程式碼

實現的效果如下:

實現效果
可以看到粒子是沿著Y軸向下成90度的一個發散角度。如果想實現火焰等效果。就可以這樣,把角度調小一點即可。

  • velocityvelocityRangexAccelerationyAccelerationzAcceleration:前面兩個是粒子的初速度和初速度的範圍,後面是三個分別是在x、y、z軸方向的加速度,這個很好理解,初中就應該知道加速度的概念,也就是每秒鐘速度的變化量。在放煙花的效果中,煙花飛上天的過程中,模擬一個收重力影響的效果,就可以通過yAcceleration模擬一個重力加速度的效果。
  • spinspinRange:這兩個屬性很重要,是粒子的自轉屬性。在粒子被髮射出去之後,想要實現自轉,就需要用到他們。**粒子的自轉是以弧度制來計算的,表示每秒鐘粒子自轉的弧度數。spin為正數代表粒子是順時針旋轉的,為負數的話就是逆時針選轉了。**舉個?:粒子的生命週期就是20秒,那麼你想讓你的粒子這個生命週期內剛好自轉12周,若spinRange為0,那麼粒子的spin值就應該為((PI/180)*360 * 2)/20,就得到了每秒需要轉動的弧度數。
5.CAEmitterCell子粒子的屬性
  • emitterCells:看到CAEmitterCell的這個屬性的時候或許會有些疑惑,不用驚訝,前面說過CAEmitterLayer可以產生cell,通用cell也可以產生cell。那麼這個屬性就和CAEmitterLayer中的emitterCells一樣,也是一個陣列。這裡有幾個需要注意的地方:
    1. 若給cell設定了subCell,若想控制subCell的方向,那麼得考慮父cell的方向屬性,也就是emissionLongtitudeemissionLatitude這兩個屬性的情況。
    2. 不管父粒子cell是從什麼樣的形狀上發射出來的,若要發射subCell,subCell總是從kCAEmitterLayerPoint形狀上由父粒子的中心發射出來的。

##造幾個小Demo

理解了CAEmitterLayerCAEmitterCell的屬性之後,通過粒子系統實現一些炫酷的動畫效果就很簡單了。接下來對實現的幾個小demo效果作個思路分享,歡迎提供更好的方法~。

QQ空間點贊動畫

動畫分析
  • 點讚的時候先是把按鈕放大再縮小,這個可以用核心動畫裡面的關鍵幀動畫CAKeyframeAnimation實現
  • 放大後馬上回有一圈的粒子發射,這就是粒子系統實現
  • 然後從贊到取消贊沒有動畫效果
實現思路
  • 自定義按鈕,重寫setHighlighted方法去掉高亮狀態。提供兩張圖片,用於預設狀態和選中狀態。
  • 配置發射源CAEmitterLayer和粒子CAEmitterCell。由於CAEmitterLayerbirthRate預設為1,CAEmitterCellbirthRate預設為0,那麼先不設定這兩個屬性。給cell設定好name,然後自定義一個動畫開始的方法,在這裡面通過KVC設定CAEmitterCellbirthRate以實現動畫
/**
 * 開始動畫
 */
- (void)startAnimation{
    
    // 用KVC設定顆粒個數
    [self.explosionLayer setValue:@1000 forKeyPath:@"emitterCells.explosionCell.birthRate"];
    
    // 開始動畫
    self.explosionLayer.beginTime = CACurrentMediaTime();
    // 延遲停止動畫
    [self performSelector:@selector(stopAnimation) withObject:nil afterDelay:0.15];
}

/**
 * 動畫結束
 */
- (void)stopAnimation{
    // 用KVC設定顆粒個數
    [self.explosionLayer setValue:@0 forKeyPath:@"emitterCells.explosionCell.birthRate"];
    [self.explosionLayer removeAllAnimations];
}
複製程式碼
  • 重寫按鈕的setSelected方法,在裡面通過關鍵幀動畫實現縮放。
/**
 * 選中狀態 實現縮放
 */
- (void)setSelected:(BOOL)selected{
    [super setSelected:selected];
    
    // 通過關鍵幀動畫實現縮放
    CAKeyframeAnimation * animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"transform.scale";
    if (selected) {  // 從沒有點選到點選狀態 會有爆炸的動畫效果
        animation.values = @[@1.5,@2.0, @0.8, @1.0];
        animation.duration = 0.5;
        
        animation.calculationMode = kCAAnimationCubic;
        [self.layer addAnimation:animation forKey:nil];

        // 讓放大動畫先執行完畢 再執行爆炸動畫
        [self performSelector:@selector(startAnimation) withObject:nil afterDelay:0.25];
    }else{ // 從點選狀態normal狀態 無動畫效果 如果點贊之後馬上取消 那麼也立馬停止動畫
        [self stopAnimation];
    }
}
複製程式碼

結語

還有幾個動畫的思路就不囉嗦了,實現起來都很簡單,關鍵是要去理解這些屬性的作用。另外動畫做起來即使費時間,要自己去理解屬性的作用的話需要花時間除錯對比,其實用其他方式也可以實現這樣的效果,但是CAEmitterLayer 基於GPU,做這些效果的時候比較方便。demo已經上傳github了,提供了下雨、下雪、紅包雨、五彩小球、愛心、火焰、煙花等效果,值得一說的是,煙花需要三個cell,一個提供發射的shootCell,一個用於爆炸的explodeCell,還有一個用於火花的sparkCell,這些都是父子關係,一個cell生命週期完了另外一個再出來。這些可以檢視程式碼體會,都有註釋~。EmitterAnimation

相關文章