How do you create a wiggle animation similar to iphone deletion animation

前端 未结 8 2291
-上瘾入骨i
-上瘾入骨i 2020-12-12 16:57

We are currently developing an application that contains a series of icons. We want the icons to wiggle like the app deletion animations when pressed. What would be the be

相关标签:
8条回答
  • 2020-12-12 17:26
        func startWiggling() {
            deleteButton.isHidden = false
            guard contentView.layer.animation(forKey: "wiggle") == nil else { return }
            guard contentView.layer.animation(forKey: "bounce") == nil else { return }
    
            let angle = 0.04
    
            let wiggle = CAKeyframeAnimation(keyPath: "transform.rotation.z")
            wiggle.values = [-angle, angle]
            wiggle.autoreverses = true
            wiggle.duration = randomInterval(0.1, variance: 0.025)
            wiggle.repeatCount = Float.infinity
            contentView.layer.add(wiggle, forKey: "wiggle")
    
            let bounce = CAKeyframeAnimation(keyPath: "transform.translation.y")
            bounce.values = [4.0, 0.0]
            bounce.autoreverses = true
            bounce.duration = randomInterval(0.12, variance: 0.025)
            bounce.repeatCount = Float.infinity
            contentView.layer.add(bounce, forKey: "bounce")
        }
    
        func stopWiggling() {
            deleteButton.isHidden = true
            contentView.layer.removeAllAnimations()
            }
    
        func randomInterval(_ interval: TimeInterval, variance: Double) -> TimeInterval {
            return interval + variance * Double((Double(arc4random_uniform(1000)) - 500.0) / 500.0)
        }
    

    Look at this iOS SpingBoard example

    springboard

    0 讨论(0)
  • 2020-12-12 17:30

    Looking at the iOS implementation a bit closer, there are two things that make theirs a bit more realistic than the code mentioned here:

    • The icons appear to have a bounce as well as a rotation
    • Every icon has its own timing -- they are not all synchronized

    I based myself on the answers here (and with some help from this answer) to add the rotation, the bounce and a bit of randomness to the duration of each animation.

    #define kWiggleBounceY 4.0f
    #define kWiggleBounceDuration 0.12
    #define kWiggleBounceDurationVariance 0.025
    
    #define kWiggleRotateAngle 0.06f
    #define kWiggleRotateDuration 0.1
    #define kWiggleRotateDurationVariance 0.025
    
    -(void)startWiggling {
        [UIView animateWithDuration:0
                         animations:^{
                             [self.layer addAnimation:[self rotationAnimation] forKey:@"rotation"];
                             [self.layer addAnimation:[self bounceAnimation] forKey:@"bounce"];
                             self.transform = CGAffineTransformIdentity;
                         }];
    }
    
    -(CAAnimation*)rotationAnimation {
        CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
        animation.values = @[@(-kWiggleRotateAngle), @(kWiggleRotateAngle)];
    
        animation.autoreverses = YES;
        animation.duration = [self randomizeInterval:kWiggleRotateDuration
                                        withVariance:kWiggleRotateDurationVariance];
        animation.repeatCount = HUGE_VALF;
    
        return animation;
    }
    
    -(CAAnimation*)bounceAnimation {
        CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.y"];
        animation.values = @[@(kWiggleBounceY), @(0.0)];
    
        animation.autoreverses = YES;
        animation.duration = [self randomizeInterval:kWiggleBounceDuration
                                        withVariance:kWiggleBounceDurationVariance];
        animation.repeatCount = HUGE_VALF;
    
        return animation;
    }
    
    -(NSTimeInterval)randomizeInterval:(NSTimeInterval)interval withVariance:(double)variance {
        double random = (arc4random_uniform(1000) - 500.0) / 500.0;
        return interval + variance * random;
    }
    

    I implemented this code on a UICollectionView which had 30 items bouncing and the performance was flawless on an iPad 2.

    0 讨论(0)
  • Edited paiego's code to fit my needs: visual error animation feedback upon user's action (tap). It happens once - it's not a constant wiggling like SpringBoard app edit wiggle animation.

    - (CAAnimation *)shakeAnimation {
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    
        CGFloat wobbleAngle = 0.06f;
    
        NSValue *valLeft;
        NSValue *valRight;
        NSMutableArray *values = [NSMutableArray new];
    
        for (int i = 0; i < 5; i++) {
            valLeft = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
            valRight = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
            [values addObjectsFromArray:@[valLeft, valRight]];
            wobbleAngle*=0.66;
        }
        animation.values = [values copy];
        animation.duration = 0.7;
        return animation;
    }
    

    Usage:

    [your_view.layer addAnimation:[self shakeAnimation] forKey:@""]; //do the shake animation
    your_view.transform = CGAffineTransformIdentity; //return the view back to original
    

    Hope this helps someone else.

    0 讨论(0)
  • 2020-12-12 17:43

    Answered in another thread a Swift 4 version of what is apparently Apple's own algorithm reverse engineered: https://stackoverflow.com/a/47730519/5018607

    0 讨论(0)
  • 2020-12-12 17:48

    The answer by Vinzius is very cool. However the wobble only rotates from 0 Radians to 0.08. Thus the wobble can look a little unbalanced. If you get this same issue then you may want to add both a negative and a positive rotation by using a CAKeyframeAnimation rather than a CABasicRotation:

    - (CAAnimation*)getShakeAnimation 
    {
        CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    
        CGFloat wobbleAngle = 0.06f;
    
        NSValue* valLeft = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
        NSValue* valRight = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
        animation.values = [NSArray arrayWithObjects:valLeft, valRight, nil];
    
        animation.autoreverses = YES;  
        animation.duration = 0.125;
        animation.repeatCount = HUGE_VALF;  
    
        return animation;    
    }
    

    You can use this animation method for your view or button like this.

    [self.yourbutton.layer addAnimation:[self getShakeAnimation] forKey:@""];
    
    0 讨论(0)
  • 2020-12-12 17:49

    SWIFT :-

    let transformAnim  = CAKeyframeAnimation(keyPath:"transform")
    transformAnim.values  = [NSValue(CATransform3D: CATransform3DMakeRotation(0.04, 0.0, 0.0, 1.0)),NSValue(CATransform3D: CATransform3DMakeRotation(-0.04 , 0, 0, 1))]
    transformAnim.autoreverses = true
    transformAnim.duration  = (Double(indexPath.row)%2) == 0 ?   0.115 : 0.105
    transformAnim.repeatCount = Float.infinity
    self.layer.addAnimation(transformAnim, forKey: "transform")
    

    Objective C :-

    -(CAKeyframeAnimation *)wiggleView
    {
        CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    
        CGFloat wobbleAngle = 0.04f;
    
        NSValue* valLeft = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)];
        NSValue* valRight = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)];
        animation.values = [NSArray arrayWithObjects:valLeft, valRight, nil];
    
        animation.autoreverses = YES;
        animation.duration = 0.125;
        animation.repeatCount = HUGE_VALF;
    
        return animation;
    }
    
    0 讨论(0)
提交回复
热议问题