來來來,今天我們們通過實現一個類似Twitter的啟動動畫來看看CAKeyFrame Animation和CAAnimation Group怎麼玩。
所以今天我們們的重點到了第七章,CAKeyFrame Animation和CAAnimation Group。最後的那個啟動動畫完全是為了實踐一下看看CAKeyFrame Animation和CAAnimation Group怎麼使用。
有讀者私下說更新速度太慢了。在碼雲上看了一下下載的統計,發現其實下載的童鞋並不是特別多。如果只是看看思路,或者複習一下這些基礎知識,確實是很快。但是如果對於這些內容不是特別熟悉,建議還是敲一邊程式碼,看看自己能碰到什麼坑。
俺寫一篇分享文章大約要4~6個小時,大體是三部分:想到合適的例子,敲程式碼寫註釋,寫文章。通常都會看自己當前的情況,決定是先寫swift版還是OC版,然後不動腦子的翻譯成另外一版調整一下BUG。這樣也是為了訓練自己,前段時間發現自己有時候會不自覺的把兩種語言混在一起,這個習慣特別不好,所以想用這種方式自己糾正一下。到最後更新寫文章的時候反而更輕鬆了,因為不用動腦。哈哈~
Come on~下面這張圖純粹是為了簡書當作封面使用的。也不知道為什麼,以前簡書還能自動把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儲存這些數值。
建立步驟:
- 建立關鍵幀動畫物件
- 設定屬性
- 新增到要作用的layer上
- 如果使用rect橢圓的方式,動畫會不連貫,停頓一下。原因是因為矩形的周長比橢圓的長,動畫路徑按照橢圓執行完之後,需要等待一下最大周長走完。
這些都是因為計算模式導致的。
1.1 建立一個抖動的小方塊
我們用一個簡單的demo來感受一下CAKeyframeAnimation,來做一個會抖動的小方塊。
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物件加入圖層後,組中所有動畫物件可以同時併發執行.
我們試著做一個包行旋轉、縮放、按一定弧度路徑組合在一起的動畫。效果如下:
- (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圖層裡面的內容才是它關心的,除此以外的一切都會被隱藏起來。
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動畫系列之九:實現點讚的動畫及播放起伏指示器
第十篇:實戰系列:繪製雲霄飛車場景