How Do You CAKeyframeAnimation Scale?

后端 未结 4 1702
盖世英雄少女心
盖世英雄少女心 2020-12-28 10:02

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.<

相关标签:
4条回答
  • 2020-12-28 10:06

    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"];
    }
    
    0 讨论(0)
  • 2020-12-28 10:15

    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) }
    
    0 讨论(0)
  • 2020-12-28 10:16

    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.

    0 讨论(0)
  • 2020-12-28 10:31

    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

    0 讨论(0)
提交回复
热议问题