2010-01-04 29 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