English 中文(简体)
How Do You CAKeyframeAnimation Scale?
原标题:

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

}

最佳回答

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

问题回答

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

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.

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




相关问题
Code sign Error

I have created a new iPhone application.I have two mach machines. I have created the certificate for running application in iPhone in one mac. Can I use the other mac for running the application in ...

ABPersonViewController Usage for displaying contact

Created a View based Project and added a contact to the AddressBook using ABAddressBookRef,ABRecordRef now i wanted to display the added contact ABPersonViewController is the method but how to use in ...

将音频Clips从Peter改为服务器

我不禁要问,那里是否有任何实例表明从Peit向服务器发送音响。 I m不关心电话或SIP风格的解决办法,只是一个简单的袖珍流程......

• 如何将搜查线重新定位?

我正试图把图像放在搜索条左边。 但是,问题始于这里,搜索条线不能重新布署。

热门标签