UIView shake animation

47,010

Solution 1

I wrote that post. It's overkill for a UIView, plus the parameters are geared toward an OSX app. Do this instead.

CABasicAnimation *animation = 
                         [CABasicAnimation animationWithKeyPath:@"position"];
[animation setDuration:0.05];
[animation setRepeatCount:8];
[animation setAutoreverses:YES];
[animation setFromValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x - 20.0f, [lockView center].y)]];
[animation setToValue:[NSValue valueWithCGPoint:
               CGPointMake([lockView center].x + 20.0f, [lockView center].y)]];
[[lockView layer] addAnimation:animation forKey:@"position"];

You'll have to play with the duration and repeatCount parameters as well as the x distance from center in the from and to values, but it should give you what you need. I hope that helps. Let me know if you have any questions.

---


Swift 3.0

let midX = lockView.center.x
let midY = lockView.center.y

let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.06
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = CGPoint(x: midX - 10, y: midY)
animation.toValue = CGPoint(x: midX + 10, y: midY)
layer.add(animation, forKey: "position")

Solution 2

I prefer this solution that has a nice springy behavior, ideal for a wrong-password shake animation.

view.transform = CGAffineTransformMakeTranslation(20, 0);
[UIView animateWithDuration:0.4 delay:0.0 usingSpringWithDamping:0.2 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    view.transform = CGAffineTransformIdentity;
} completion:nil];

Swift 3

extension UIView {
    func shake() {
        self.transform = CGAffineTransform(translationX: 20, y: 0)
        UIView.animate(withDuration: 0.4, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {
            self.transform = CGAffineTransform.identity
        }, completion: nil)
    }
}

Solution 3

Here's my nice and simple looking version This simulates the shake you get on Mac OS X when you do an incorrect login. You could add this as a category on UIView if you like.

@implementation UIView (DUExtensions)

- (void) shake {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    animation.duration = 0.6;
    animation.values = @[ @(-20), @(20), @(-20), @(20), @(-10), @(10), @(-5), @(5), @(0) ];
    [self.layer addAnimation:animation forKey:@"shake"];  
}

@end

The animation values are the x offset from the views current position. Positive values shifting the view to the right, and negative values to the left. By successively lowering them, you get a shake that naturally loses momentum. You can tweak these numbers if you like.

Solution 4

Here is the swift version as an extension in case anybody needs it

extension UIImageView{
    func vibrate(){
        let animation = CABasicAnimation(keyPath: "position")
        animation.duration = 0.05
        animation.repeatCount = 5
        animation.autoreverses = true
        animation.fromValue = NSValue(CGPoint: CGPointMake(self.center.x - 2.0, self.center.y))
        animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 2.0, self.center.y))
        self.layer.addAnimation(animation, forKey: "position")
    }
}

This will animate an small UIImageView (around 15x15). If you need to animate something bigger you may want to change the 2.0 factor of movement to something greater.

Solution 5

Based on @bandejapaisa answer, UIView extension for Swift 3

extension UIView {
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.duration = 0.6
        animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
        layer.addAnimation(animation, forKey: "shake")
    }
}
Share:
47,010
Jack Greenhill
Author by

Jack Greenhill

Full-stack developer—primarily working in TypeScript (Angular/RxJS), but Swift is my true love.

Updated on August 15, 2020

Comments

  • Jack Greenhill
    Jack Greenhill over 3 years

    i'm trying to make a UIView shake when a button is pressed.

    I am adapting the code I found on http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/.

    However, by trying to adapt the following code to shake a UIView, it does not work:

    - (void)animate {
        const int numberOfShakes = 8;
        const float durationOfShake = 0.5f;
        const float vigourOfShake = 0.1f;
    
        CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animation];
    
        CGRect frame = lockView.frame;
    
        CGMutablePathRef shakePath = CGPathCreateMutable();
        CGPathMoveToPoint(shakePath, NULL, CGRectGetMinX(frame), CGRectGetMinY(frame));
    
        for (int index = 0; index < numberOfShakes; ++index) {
            CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) - frame.size.width * vigourOfShake, CGRectGetMinY(frame));
    
            CGPathAddLineToPoint(shakePath, NULL, CGRectGetMinX(frame) + frame.size.width * vigourOfShake, CGRectGetMinY(frame));
        }
    
        CGPathCloseSubpath(shakePath);
    
        shakeAnimation.path = shakePath;
        shakeAnimation.duration = durationOfShake;
    
    
        [lockView.layer addAnimation:shakeAnimation forKey:@"frameOrigin"];
    
    }
    
  • Pedro Borges
    Pedro Borges about 9 years
    Great looks and sound idea to embed this into a UIView category. UIViews should shake, period!
  • Theo
    Theo over 8 years
    When used at a slower speed (i.e. longer duration) this animation is much smoother than the one from the other answer that uses repeatCount.
  • Jordan Smith
    Jordan Smith about 8 years
    Some thoughts after going to use this code. Timing Function - defaults to linear so not necessary to set it. Animation Values - you could go a step further and define a function to produce nice mathematical values... this works too though :)
  • Crashalot
    Crashalot almost 8 years
    how do you repeat this? it only happens once right now.
  • Ortwin Gentz
    Ortwin Gentz almost 8 years
    If I understand the OP correctly, he wanted a short shake animation. Since in real life a shake movement has friction and slows down over time, I find my solution most appropriate. If you want to make it shake longer, experiment with the damping and initialVelocity parameters. If you want to repeat it indefinitely go with one of the other solutions.
  • Crashalot
    Crashalot almost 8 years
    this animation was the best, agreed. just want to repeat it a few times, that's all.
  • Ortwin Gentz
    Ortwin Gentz almost 8 years
    If you just want to extend it, try to play with the duration, damping and initialVelocity values.
  • Jorge Wander Santana Ureña
    Jorge Wander Santana Ureña over 7 years
    Thanks, i use your answer to build it in Xamarin IOS If anyone would like to use it, here it is: gist.github.com/jorwan/1ed57459c7b01b5a5b1135219e6219cf
  • Ehtesham Hasan
    Ehtesham Hasan over 6 years
    @Matt What if I want to shake randomly, so the UIView moves at random directions on each shake?
  • Matt Long
    Matt Long over 6 years
    @EhteshamHasan it couldn't be truly random. The positions/points would have to be within a range and you may not want it to shake between the extremes (corner to corner for example) of that range (though that's up to you). The simple answer is put the possible positions (CGPoints) in an array and seed a random number generator that provides an index less than the count of points in your array and then move the position to that point using the same technique described in my answer.
  • Lirik
    Lirik over 6 years
    I would add a completion block from this extension.
  • Yuri Grigoriev
    Yuri Grigoriev over 5 years
    This solution is much better because of possibility to use completion handler.
  • ilkayaktas
    ilkayaktas almost 5 years
    Last line should be fixed with self.layer.add(animation, forKey: "shake")
  • rmaddy
    rmaddy over 4 years
    I had good results replicating the standard iOS passcode screen shake using this code with a duration of 0.4, damping of 0.03, spring velocity of 1.2 and an initial X transform of 35.