iOS動畫系列之七:實現類似Twitter的啟動動畫

非典型技術宅發表於2019-02-26

來來來,今天我們們通過實現一個類似Twitter的啟動動畫來看看CAKeyFrame Animation和CAAnimation Group怎麼玩。

所以今天我們們的重點到了第七章,CAKeyFrame Animation和CAAnimation Group。最後的那個啟動動畫完全是為了實踐一下看看CAKeyFrame Animation和CAAnimation Group怎麼使用。

有讀者私下說更新速度太慢了。在碼雲上看了一下下載的統計,發現其實下載的童鞋並不是特別多。如果只是看看思路,或者複習一下這些基礎知識,確實是很快。但是如果對於這些內容不是特別熟悉,建議還是敲一邊程式碼,看看自己能碰到什麼坑。

俺寫一篇分享文章大約要4~6個小時,大體是三部分:想到合適的例子,敲程式碼寫註釋,寫文章。通常都會看自己當前的情況,決定是先寫swift版還是OC版,然後不動腦子的翻譯成另外一版調整一下BUG。這樣也是為了訓練自己,前段時間發現自己有時候會不自覺的把兩種語言混在一起,這個習慣特別不好,所以想用這種方式自己糾正一下。到最後更新寫文章的時候反而更輕鬆了,因為不用動腦。哈哈~

Come on~下面這張圖純粹是為了簡書當作封面使用的。也不知道為什麼,以前簡書還能自動把GIF的第一楨當作封面,現在不好使了。

CAKeyFrame Animation和CAAnimation Group.png
CAKeyFrame Animation和CAAnimation Group.png

下面展示一下寫完之後的成果:

ani.gif
ani.gif

原始碼可以在這裡下載,裡面有OC和Swift兩版。git.oschina.net/atypical/CA…

iOS動畫系列之CAKeyFrame Animation和CAAnimation Group(OC和Swift兩版)

1. CAKeyframeAnimation

CAKeyframeAnimation是CApropertyAnimation的子類,跟CABasicAnimation的區別是:CABasicAnimation只能從一個數值(fromValue)變到另一個數值(toValue),而CAKeyframeAnimation會使用一個NSArray儲存這些數值。

建立步驟:

  1. 建立關鍵幀動畫物件
  2. 設定屬性
  3. 新增到要作用的layer上
  • 如果使用rect橢圓的方式,動畫會不連貫,停頓一下。原因是因為矩形的周長比橢圓的長,動畫路徑按照橢圓執行完之後,需要等待一下最大周長走完。
    這些都是因為計算模式導致的。

1.1 建立一個抖動的小方塊

我們用一個簡單的demo來感受一下CAKeyframeAnimation,來做一個會抖動的小方塊。

抖動的小方塊.gif
抖動的小方塊.gif

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
//設定一些列的關鍵幀動畫
    animation.values = @[@(-M_PI_4 / 5),@(M_PI_4 / 5),@(-M_PI_4 / 5)];
    animation.repeatCount = CGFLOAT_MAX;
    [self.view.layer addAnimation:animation forKey:@"rotation"];複製程式碼

1.2 建立一個沿橢圓路徑運動的小飛機

我們建立一個UIBezierPath,讓小飛機沿著這個路徑運動。

//建立動畫物件
    CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//設定屬性:建立beziper路徑,並把路徑作為運動軌跡
    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 500)];
    keyFrameAnimation.path = bezierPath.CGPath;
//設定動畫時間
    keyFrameAnimation.duration = 2;
//設定動畫迴圈播放的次數
    keyFrameAnimation.repeatCount = CGFLOAT_MAX;
//設定動畫的計算模式
    keyFrameAnimation.calculationMode = kCAAnimationPaced;

//將動畫新增到layer上
    [self.planeView.layer addAnimation:keyFrameAnimation forKey:nil];複製程式碼

1.3 動畫疊加

剛才新增了一個沿路徑運動的飛機,我們同時還可以給飛機再把抖動的那個動畫也新增上去。前幾篇提到後面那個forKey,可能還有童鞋不知道幹啥用。現在看到了木有?一個layer裡面好幾個動畫,如何找到對應的動畫吶?現在通過這個key就能找到了。

    //        為小飛機同時新增抖動的動畫和橢圓路徑旋轉的動畫
    [self.planeImageView.layer addAnimation:[self shakeAni] forKey:nil];
    [self.planeImageView.layer addAnimation:[self ovalAni] forKey:nil];複製程式碼

2. CAAnimationGroup

單一的動畫在實際中往往是不能滿足需求的,這時就需要用到動畫組。

  • 是CAAnimation的子類
  • 可以儲存一組動畫物件,將CAAnimationGroup物件加入圖層後,組中所有動畫物件可以同時併發執行.

我們試著做一個包行旋轉、縮放、按一定弧度路徑組合在一起的動畫。效果如下:

arcAni.gif
arcAni.gif

- (CAAnimationGroup *)groupAni{
    //        例項化一個組動畫物件
        CAAnimationGroup *groupAni = [[CAAnimationGroup alloc] init];

    //        建立旋轉的動畫
        CABasicAnimation *basicRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    basicRotation.toValue = @(M_PI * 2);

    //        建立縮放的動畫
        CABasicAnimation *basicScale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    basicScale.toValue = @(0.2);

    //        建立按照路徑移動的動畫
        CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    UIBezierPath *arcPath = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:150 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

    keyFrameAni.path = arcPath.CGPath;
    keyFrameAni.calculationMode = kCAAnimationPaced;
    keyFrameAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    //        將旋轉、縮放、移動的動畫新增到組動畫中
    groupAni.animations = @[basicRotation,basicScale,keyFrameAni];
    //        組動畫重複次數
        groupAni.repeatCount = CGFLOAT_MAX;
    //        組動畫時長
        groupAni.duration = 2;

    return groupAni;
}複製程式碼

3. 實現類似Twitter的啟動動畫

3.1實現思路

1,在View上設定一個東西能夠遮擋住背景圖;
2,把遮罩變成五角星;
3,讓遮罩慢慢變大,中間可見區域越來越大。

yes!思路就是這樣的。那怎麼遮住背景圖片呢?

3.2 CALayer的遮罩屬性

CALayer本身有一個屬性,叫mask。我們來看一下官方解釋:

 @property(nullable, strong) CALayer *mask;

When true an implicit mask matching the layer bounds is applied to
the layer (including the effects of the `cornerRadius' property). If
both `mask' and `masksToBounds' are non-nil the two masks are
multiplied to get the actual mask values. Defaults to NO.
Animatable.複製程式碼

它類似於一個子圖層,相對於父圖層(即擁有該屬性的圖層)佈局,但是它卻不是一個普通的子圖層。不同於其他能夠在父圖層中繪製出影象的子圖層,mask圖層定義了父圖層的部分可見區域。

mask圖層的Color屬性是無關緊要的,真正重要的是圖層的輪廓。也就是說mask圖層實心的部分會被保留下來,其他的則會被拋棄。如果mask圖層比父圖層要小,只有在mask圖層裡面的內容才是它關心的,除此以外的一切都會被隱藏起來。

Paste_Image.png
Paste_Image.png

3.3 實現類似Twitter的啟動動畫

好了準備工作都做完了,我們就開始寫這個動畫了。這個動畫其實就是一個簡單的CAKeyframeAnimation。設定了三個關鍵幀動畫的大小,以及這三個關鍵幀的運動節奏。

然後,就好啦~然後,就好啦~然後,就好啦~然後,就好啦~

哪尼?!!!就這樣?!!對啊,就這樣。

 - (CAKeyframeAnimation *)maskAni{
 //        放大縮小檢視,keypath使用bounds
 CAKeyframeAnimation *maskAni = [CAKeyframeAnimation animationWithKeyPath:@"bounds"];
 //        動畫時間
 maskAni.duration = 30.75;
 //        動畫延遲0.5秒播放
 maskAni.beginTime = CACurrentMediaTime() + 0.5;


 //        設定關鍵幀動畫的數值
 CGRect startRect = self.maskLayer.frame;

 CGRect tempRect = CGRectMake(0, 0, 100, 100);

 CGRect finalRect = CGRectMake(0, 0, 2000, 2000);
 maskAni.values = @[[NSValue valueWithCGRect:startRect],[NSValue valueWithCGRect:tempRect],[NSValue valueWithCGRect:finalRect]];


 //        設定關鍵幀動畫的運動節奏
 maskAni.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];


 //        動畫播放結束後是否移除動畫
 maskAni.removedOnCompletion = NO;

 //        動畫填充模式:kCAFillModeForwards:當動畫結束後,layer會一直保持著動畫最後的狀態
 maskAni.fillMode = kCAFillModeForwards;

 return maskAni;


 }複製程式碼

留一個小問題

我在OC和Swift裡面對不同的View使用了mask。一個是給背景圖片的UIImageView設定了mask,另一個是直接給Controller的View設定了mask。設定這兩個有神馬區別咩?


好,下篇其實有一個重頭,就是CAShapeLayer。因為在工作中碰到的大部分動畫都是通過UIView的動畫block實現,其他都基本上都是需要用到CAShapeLayer。我們下次玩點好玩的吧~
如果還有興趣,可以看看本系列的其他文章哈。

-----------------------華麗分割線,iOS動畫系列全集連結-------------------------------------------------
第一篇:iOS動畫系列之一:通過實戰學習CALayer和透視的原理。做一個帶時分秒指標的時鐘動畫(上)
第二篇:iOS動畫系列之二:通過實戰學習CALayer和透視的原理。做一個帶時分秒指標的時鐘動畫。包含了OC和Swift兩種原始碼(下)
第三篇:iOS動畫系列之三:Core Animation。介紹了Core Animation的常用屬性和方法。
第四篇:CABasic Animation。iOS動畫系列之四:基礎動畫之平移篇
第五篇:CABasic Animation。iOS動畫系列之五:基礎動畫之縮放篇&旋轉篇
第六篇:iOS動畫系列之六:利用CABasic Animation完成帶動畫特效的登入介面
第七篇:iOS動畫系列之七:實現類似Twitter的啟動動畫
第八篇:iOS動畫系列之八:使用CAShapeLayer繪畫動態流量圖
第九篇:iOS動畫系列之九:實現點讚的動畫及播放起伏指示器
第十篇:實戰系列:繪製過山車場景

相關文章