2010-01-04 28 views
10

我想用幾個關鍵幀創建一個動畫。我想我的圖層(在這種情況下,一個按鈕) 放大到1.5然後下降到0.5然後到1.2然後下降到0.8然後1.0。你如何CAKeyframeAnimation比例?

我也想EaseIn和EaseOut的每個關鍵幀。

您可以想象,這會在現場創造出彈跳/彈跳效果。

在我的應用程序的其他部分,我一直在使用CAKeyframeAnimation(參見下面的代碼)。 這會創建一個類似的彈性動畫,但對於x和y位置。

我可以修改下面的代碼來影響縮放而不是位置嗎?

預先感謝您!

- (CAAnimation*)monInAnimation { 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathMoveToPoint(path,NULL,113,320); 
CGPathAddLineToPoint(path, NULL, 113.5, 283); 
CGPathAddLineToPoint(path, NULL, 113.5, 179); 
CGPathAddLineToPoint(path, NULL, 113.5, 207); 
CGPathAddLineToPoint(path, NULL, 113.5, 187); 
CGPathAddLineToPoint(path, NULL, 113.5, 199); 
CGPathAddLineToPoint(path, NULL, 113.5, 193); 
CGPathAddLineToPoint(path, NULL, 113.5, 195); 
CGPathAddLineToPoint(path, NULL, 113.5, 194); 

CAKeyframeAnimation * 
animation = [CAKeyframeAnimation 
      animationWithKeyPath:@"position"]; 

[animation setPath:path]; 
[animation setDuration:1.5]; 
[animation setCalculationMode:kCAAnimationLinear]; 
NSArray *arr = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], 
[NSNumber numberWithFloat:0.12], 
[NSNumber numberWithFloat:0.24], 
[NSNumber numberWithFloat:0.36], 
[NSNumber numberWithFloat:0.48], 
[NSNumber numberWithFloat:0.60], 
[NSNumber numberWithFloat:0.72], 
[NSNumber numberWithFloat:0.84], 
[NSNumber numberWithFloat:1.0],nil]; 

[animation setKeyTimes:arr]; 
[animation setTimingFunctions:[NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], nil]]; 
//[animation setAutoreverses:YES]; 
CFRelease(path); 
return animation; 

}

- (void)monBtnIn { 

[monButton.layer setPosition:CGPointMake(113.5,194)]; 
[monButton.layer addAnimation:[self monInAnimation] 
        forKey:@"position"]; 

}

回答

27

有兩種解決方案:

首先,你還可以在動畫轉換屬性。

使用Brad的代碼,但使用@「transform」作爲keypath。主要優點是,你不必計算實際的框架,而是提供一個簡單的比例因子:

Objective-C的

CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 

CATransform3D startingScale = CATransform3DScale (layer.transform, 0, 0, 0); 
CATransform3D overshootScale = CATransform3DScale (layer.transform, 1.2, 1.2, 1.0); 
CATransform3D undershootScale = CATransform3DScale (layer.transform, 0.9, 0.9, 1.0); 
CATransform3D endingScale = layer.transform; 

NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCATransform3D:startingScale], 
                [NSValue valueWithCATransform3D:overshootScale], 
                [NSValue valueWithCATransform3D:undershootScale], 
                [NSValue valueWithCATransform3D:endingScale], nil]; 
[boundsOvershootAnimation setValues:boundsValues]; 

NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f], 
        [NSNumber numberWithFloat:0.5f], 
        [NSNumber numberWithFloat:0.9f], 
        [NSNumber numberWithFloat:1.0f], nil];  
[boundsOvershootAnimation setKeyTimes:times]; 


NSArray *timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          nil]; 
[boundsOvershootAnimation setTimingFunctions:timingFunctions]; 
boundsOvershootAnimation.fillMode = kCAFillModeForwards; 
boundsOvershootAnimation.removedOnCompletion = NO; 

斯威夫特4

let boundsOvershootAnimation = CAKeyframeAnimation(keyPath: "transform") 

let startingScale = CATransform3DScale(layer.transform, 0, 0, 0) 
let overshootScale = CATransform3DScale(layer.transform, 1.2, 1.2, 1.0) 
let undershootScale = CATransform3DScale(layer.transform, 0.9, 0.9, 1.0) 
let endingScale = layer.transform 

boundsOvershootAnimation.values = [startingScale, overshootScale, undershootScale, endingScale] 

boundsOvershootAnimation.keyTimes = [0.0, 0.5, 0.9, 1.0].map { NSNumber(value: $0) } 

boundsOvershootAnimation.timingFunctions = [ 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseOut), 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut), 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut) 
] 

boundsOvershootAnimation.fillMode = kCAFillModeForwards 
boundsOvershootAnimation.isRemovedOnCompletion = false 

其次,也許更容易一點,就是使用FTUtils,一個用於核心動畫的開源包裝器。它包含一個股票「彈性」的動畫。 http://github.com/neror/ftutils

+1

This works great ... Thank you。我確實加了一個。 我會檢查FTUtilis - 謝謝。 – Jonathan 2010-01-05 00:55:41

+2

您可以通過使用Keypath作爲「transform.scale」來使用數字。不是嗎? – 2012-10-07 10:43:50

4

我不知道,如果你可以使用一個CAKeyframeAnimation爲動畫一個UIView的規模,但你可以用CABasicAnimation和設置做fromValue和Value屬性,並使用它來動畫變換屬性:

- (CAAnimation*)monInAnimation 
{ 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; 
    animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]; 
    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3.0, 3.0, 3.0)]; 
    [animation setDuration:1.5]; 
    [animation setAutoreverses:YES]; 
    return animation; 
} 

- (IBAction)monBtnIn 
{ 
    [monButton.layer addAnimation:[self monInAnimation] forKey:@"transform"]; 
} 
+1

謝謝akosma! 我試過這種縮放的方式,但我不知道如何添加超過2個關鍵幀。用'setAutoreverses'它從A到B然後回到A.我想從A到B到C到D. 你知道你是否可以添加更多'fromValues'和'ToValues'? 謝謝 – Jonathan 2010-01-04 11:29:46

+0

查看CAAnimationGroup類。它從CAAnimation繼承,並且可以「鏈接」各個CABasicAnimations,每個都有自己的fromValue和toValue。可能這是你在找什麼? – 2010-01-04 14:49:46

+0

從頭開始,我檢查了文檔,看起來CAAnimationGroup中的動畫是同時運行的,而不是一個接一個地運行。遊民。您應該爲動畫設置代表,然後在上一個動畫完成時開始新的動畫。 – 2010-01-04 14:57:11

8

R除了設置CAKeyframeAnimation的路徑之外,您還需要自己設置關鍵幀。我已經動畫化層的範圍的大小創造了一個「彈出式」生效前:

CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"]; 
CGSize startingSize = CGSizeZero; 
CGSize overshootSize = CGSizeMake(targetSize.width * (1.0f + POPINOVERSHOOTPERCENTAGE), targetSize.height * (1.0f + POPINOVERSHOOTPERCENTAGE)); 
CGSize undershootSize = CGSizeMake(targetSize.width * (1.0f - POPINOVERSHOOTPERCENTAGE), targetSize.height * (1.0f - POPINOVERSHOOTPERCENTAGE)); 
NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCGSize:startingSize], 
         [NSValue valueWithCGSize:overshootSize], 
         [NSValue valueWithCGSize:undershootSize], 
         [NSValue valueWithCGSize:targetSize], nil]; 
[boundsOvershootAnimation setValues:boundsValues]; 

NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f], 
        [NSNumber numberWithFloat:0.5f], 
        [NSNumber numberWithFloat:0.9f], 
        [NSNumber numberWithFloat:1.0f], nil];  
[boundsOvershootAnimation setKeyTimes:times]; 


NSArray *timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          nil]; 
[boundsOvershootAnimation setTimingFunctions:timingFunctions]; 
boundsOvershootAnimation.fillMode = kCAFillModeForwards; 
boundsOvershootAnimation.removedOnCompletion = NO; 

其中POPINOVERSHOOTPERCENTAGE是我想衝過層的目標大小的分數。你

+0

謝謝布拉德。這正是我之後的那種控制。 – Jonathan 2010-01-05 00:56:31

12

transform.scale,任何人:

你可以怎麼做呢?

let anim = CAKeyframeAnimation(keyPath: "transform.scale") 
anim.values = [0, 1, 0, 1, 0, 1, 0] 
anim.duration = 4.0 

smallView.layer.addAnimation(anim, forKey: "what") 

完全無關,如果你要使用的數值數組中漂浮,則必須將其添加爲NSNumbers,否則,他們剛剛結束了爲0!

anim.values = [0.0, 1.2, 0.9, 1.0].map { NSNumber(double: $0) } 
+0

我正在使用「transform」,但是這造成了'rotationMode = kCAAnimationRotateAuto'的問題。使用「transform.scale」也使值聲明更簡單。非常感謝。 – Henrik 2016-02-15 20:35:07