How do you create a wiggle animation similar to ip

2019-01-21 04:10发布

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 best way to code this animation sequence?

8条回答
倾城 Initia
2楼-- · 2019-01-21 04:34

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;
}
查看更多
Animai°情兽
3楼-- · 2019-01-21 04:41

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

查看更多
Melony?
4楼-- · 2019-01-21 04:46
    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

查看更多
我命由我不由天
5楼-- · 2019-01-21 04:47

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.

查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-01-21 04:48

Rewrote Sebastien's answer in Swift 3.

let wiggleBounceY = 4.0
let wiggleBounceDuration = 0.12
let wiggleBounceDurationVariance = 0.025

let wiggleRotateAngle = 0.06
let wiggleRotateDuration = 0.10
let wiggleRotateDurationVariance = 0.025

func randomize(interval: TimeInterval, withVariance variance: Double) -> Double{
    let random = (Double(arc4random_uniform(1000)) - 500.0) / 500.0
    return interval + variance * random
}

func startWiggle(for view: UIView){

    //Create rotation animation
    let rotationAnim = CAKeyframeAnimation(keyPath: "transform.rotation.z")
    rotationAnim.values = [-wiggleRotateAngle, wiggleRotateAngle]
    rotationAnim.autoreverses = true
    rotationAnim.duration = randomize(interval: wiggleRotateDuration, withVariance: wiggleRotateDurationVariance)
    rotationAnim.repeatCount = HUGE

    //Create bounce animation
    let bounceAnimation = CAKeyframeAnimation(keyPath: "transform.translation.y")
    bounceAnimation.values = [wiggleBounceY, 0]
    bounceAnimation.autoreverses = true
    bounceAnimation.duration = randomize(interval: wiggleBounceDuration, withVariance: wiggleBounceDurationVariance)
    bounceAnimation.repeatCount = HUGE

    //Apply animations to view
    UIView.animate(withDuration: 0) {
        view.layer.add(rotationAnim, forKey: "rotation")
        view.layer.add(bounceAnimation, forKey: "bounce")
        view.transform = .identity
    }
}

func stopWiggle(for view: UIView){
    view.layer.removeAllAnimations()
}
查看更多
唯我独甜
7楼-- · 2019-01-21 04:48

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.

查看更多
登录 后发表回答