如何调整关键帧动画比例?

发布于 2024-08-17 05:01:12 字数 2720 浏览 3 评论 0原文

我想创建一个包含多个关键帧的动画。我想要我的图层(在本例中是一个按钮) 放大到 1.5,然后缩小到 0.5,然后放大到 1.2,然后缩小到 0.8,然后 1.0。

我还想要每个关键帧的 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"];

}

I want to create an animation with several key frames. I want my Layer (a button in this case)
to scale up to 1.5 then down to 0.5 then up to 1.2 then down to 0.8 then 1.0.

I also want to EaseIn and EaseOut of each keyframe.

As you can imagine, this will create a Springy/Bounce effect on the spot.

In other parts of my app I have been using CAKeyframeAnimation like this (see below code).
This creates a similar springy animation but for x and y position.

Can I adapt the below code to affect scale instead of position?

Thank you in advance!

- (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"];

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

×纯※雪 2024-08-24 05:01:12

为您提供两种替代解决方案:

首先,您还可以为变换属性设置动画。

使用 Brad 的代码,但使用 @"transform" 作为键路径。主要优点是您不必计算实际帧,而是提供一个简单的缩放因子:

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;

Swift 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

Two alternative solutions for you:

First, You can also animate the transform property.

Using Brad's code, but using @"transform" for the keypath. The primary advantage being that you do not have to calculate the actual frame, but instead provide a simple scaling factor:

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;

Swift 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

Second, and likely easier, is using FTUtils, an open source wrapper for core animation. It includes a stock "springy" animation.

You can get it at:
http://github.com/neror/ftutils

终难遇 2024-08-24 05:01: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) }

transform.scale, anyone?

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")

Totally unrelated, if you are gonna use floats in the values array, you must add them as NSNumbers, otherwise they'd just end up as 0s!

anim.values = [0.0, 1.2, 0.9, 1.0].map { NSNumber(double: $0) }
雨落星ぅ辰 2024-08-24 05:01:12

您不需要设置 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 是我想要超出图层目标大小的分数。

Rather than setting the path of your CAKeyframeAnimation, you'll want to set the keyframes themselves. I've created a "pop-in" effect before by animating the size of the bounds of a layer:

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;

where POPINOVERSHOOTPERCENTAGE is the fraction by which I wanted to overshoot the target size of the layer.

冷血 2024-08-24 05:01:12

我不知道是否可以使用 CAKeyframeAnimation 来动画 UIView 的比例,但您可以使用 CABasicAnimation 并设置 fromValue 和 toValue 属性,然后使用它来动画转换属性:

- (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"];
}

I don't know if you can use a CAKeyframeAnimation for animating the scale of a UIView, but you can do it with a CABasicAnimation and setting the fromValue and toValue properties, and using that to animate the transform property:

- (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"];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文