iOS 關鍵幀動畫

QiShare發表於2018-11-05

級別:★★☆☆☆
標籤:「iOS CAKeyframeAnimation」「iOS 關鍵幀動畫」「CAKeyframeAnimation values」「CAKeyframeAnimation path」
作者: Xs·H
審校: QiShare團隊

最近的專案需求涉及到一些動畫效果。對於基本的動畫,可以使用QiShare之前分享過的CABasicAnimation實現,而和路徑相關的動畫(例如圖1的折線動畫)可以使用CAKeyframeAnimation實現。

圖1 折線動畫效果

CAKeyframeAnimation和CABasicAnimation都是CAPropertyAnimation的子類。CABasicAnimation可以控制動畫的起點(fromValue)和終點(toValue),而CAKeyframeAnimation可以控制動畫的全過程。所以,可以將CABasicAnimation理解成只關注起點和終點的CAKeyframeAnimation。

對比CABasicAnimation來說,CAKeyframeAnimation是通過控制動畫的關鍵幀步調 (關鍵幀執行的時間)來控制動畫過程的。

1、CAKeyframeAnimation使用“values”或“path”屬性來控制動畫的關鍵幀

values:可選的NSArray物件,存放多個value,每個value就是一個keyframe(關鍵幀)。在動畫過程中,關鍵幀會依序顯示出來。 path:可選的CGPathRef物件,指定動畫的路徑,可讓CALayer的anchorPointposition按照路徑變化。除了“moveTo”之外,路徑中的每個點都是一個關鍵幀。如果需要沿路徑勻速動畫,需要將calculationMode屬性設定為paced。當pathnil時,values屬性被覆蓋。

2、CAKeyframeAnimation使用“keyTimes”屬性來控制動畫的步調

keyTimes: 可選的NSArray物件,存放多個keyTime,每個keyTime都是[0, 1]區間內的浮點數所對應的NSNumber,與values中的關鍵幀一一對應,控制關鍵幀發生的時間。 PS:當valuespath覆蓋時,keyTimes作用於path。(path的優先順序較高)

3、使用CAKeyframeAnimation實現圖1的折線動畫效果

為了輔助分析動畫過程,我們為動畫加上軌跡(後文只分析動畫本身,不分析軌跡),如圖2。

圖2 帶軌跡的折線動畫效果

1) 像使用CABasicAnimation一樣初始化CAKeyframeAnimation的物件
// 初始化動畫
self.animation = [CAKeyframeAnimation animation];
self.animation.keyPath = @"position";
self.animation.delegate = self;
self.animation.duration = 5.0;
self.animation.repeatCount = 1.0;
self.animation.removedOnCompletion = NO;
self.animation.fillMode = kCAFillModeForwards;
self.animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
複製程式碼
2) 使用“values”和“keyTimes”屬性設定動畫的關鍵幀和步調
// 設定動畫的關鍵幀陣列
self.animation.values = @[[NSValue valueWithCGPoint:self.imageView.center],// 不能省略起點(1, 1)
                          [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 2, self.squareSide * 1}],// 右移1格
                          [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 2, self.squareSide * 5}],// 下移4格
                          [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 5, self.squareSide * 5}],// 右移3格
                          [NSValue valueWithCGPoint:(CGPoint){self.squareSide * 5, self.squareSide * 7}]// 下移2格
                          ];
// 設定動畫的步調
self.animation.keyTimes = @[@.0, @.1, @.5, @.8, @1.0];
// self.animation.calculationMode = kCAAnimationPaced;// 可以替代上面的keyTimes實現勻速效果
複製程式碼

PS: 上述程式碼中的keyTimes是根據values的值進行設定的,以達到動畫勻速的效果。若不設定keyTimes,動畫時長(duration)將被平均分配給4段動畫。

3) 像使用CABasicAnimation一樣為layer新增動畫和移除動畫
if (start) {
    [self.imageView.layer addAnimation:_animation forKey:@"animation"];// 執行動畫
}
else {
    [self.imageView.layer removeAnimationForKey:@"animation"];// 移除動畫
}
複製程式碼

上面有介紹到,path屬性同樣可以設定動畫的關鍵幀,並且當path不為nil時會覆蓋values。 所以,**步驟2)**可以替換為“path”“keyTimes”的方式。

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, self.imageView.center.x, self.imageView.center.y);
CGPathAddLineToPoint(path, NULL, self.squareSide * 2, self.squareSide * 1);// 右移1格
CGPathAddLineToPoint(path, NULL, self.squareSide * 2, self.squareSide * 5);// 下移4格
CGPathAddLineToPoint(path, NULL, self.squareSide * 5, self.squareSide * 5);// 右移3格
CGPathAddLineToPoint(path, NULL, self.squareSide * 5, self.squareSide * 7);// 下移2格
self.animation.keyTimes = @[@.0, @.1, @.5, @.8, @1.0];
// self.animation.calculationMode = kCAAnimationPaced;// 可以替代上面的keyTimes實現勻速效果
self.animation.path = path;
CGPathRelease(path);
複製程式碼

4、使用CAKeyframeAnimation實現曲線動畫

CAKeyframeAnimation的valuespath屬性具有強大的功能,尤其是path,可以方便的制定自定義動畫路徑,比如圖3的橢圓動畫效果。

圖3 橢圓動畫效果

使用path制定上述橢圓路徑的程式碼如下:

CGRect drawRect = (CGRect){self.squareSide, self.squareSide, self.squareSide * 8, self.squareSide * 6};
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddEllipseInRect(path, NULL, drawRect);
self.animation.keyTimes = @[@.0, @.25, @0.5, @0.75, @1.0];
// self.animation.calculationMode = kCAAnimationPaced;
self.animation.path = path;
複製程式碼

示例原始碼可從GitHub的QiShare開源庫中獲取。


關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)

推薦文章:
iOS 繪製漸變·基礎篇
iOS 繪製漸變·例項篇
iOS 編寫高質量Objective-C程式碼(七)
奇舞週刊

相關文章