UIView shake animation
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")
}
}
Jack Greenhill
Full-stack developer—primarily working in TypeScript (Angular/RxJS), but Swift is my true love.
Updated on August 15, 2020Comments
-
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 about 9 yearsGreat looks and sound idea to embed this into a UIView category. UIViews should shake, period!
-
Theo over 8 yearsWhen 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 about 8 yearsSome 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 almost 8 yearshow do you repeat this? it only happens once right now.
-
Ortwin Gentz almost 8 yearsIf 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 almost 8 yearsthis animation was the best, agreed. just want to repeat it a few times, that's all.
-
Ortwin Gentz almost 8 yearsIf you just want to extend it, try to play with the duration, damping and initialVelocity values.
-
Jorge Wander Santana Ureña over 7 yearsThanks, 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 over 6 years@Matt What if I want to shake randomly, so the UIView moves at random directions on each shake?
-
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 over 6 yearsI would add a completion block from this extension.
-
Yuri Grigoriev over 5 yearsThis solution is much better because of possibility to use completion handler.
-
ilkayaktas almost 5 yearsLast line should be fixed with self.layer.add(animation, forKey: "shake")
-
rmaddy over 4 yearsI 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.