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-e
Here is a version using,
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
Introduced in iOS 7.
const CGFloat xDelta = 16.0f;
[UIView animateKeyframesWithDuration:0.50f
delay:0.0f
options:UIViewKeyframeAnimationOptionCalculationModeLinear
animations:^{
[UIView addKeyframeWithRelativeStartTime:0.0
relativeDuration:(1.0/6.0)
animations:^{
self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta, 0.0);
}];
[UIView addKeyframeWithRelativeStartTime:(1.0/6.0)
relativeDuration:(1.0/6.0)
animations:^{
self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(-xDelta, 0.0);
}];
[UIView addKeyframeWithRelativeStartTime:(1.0/3.0)
relativeDuration:(1.0/3.0)
animations:^{
self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformMakeTranslation(xDelta/2.0, 0.0);
}];
[UIView addKeyframeWithRelativeStartTime:(2.0/3.0)
relativeDuration:(1.0/3.0)
animations:^{
self.passwordTextField.transform = self.usernameTextField.transform = CGAffineTransformIdentity;
}];
}
completion:NULL];
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")
Swift 3 implementation based on @Mihael-Isaev answer
private enum Axis: StringLiteralType {
case x = "x"
case y = "y"
}
extension UIView {
private func shake(on axis: Axis) {
let animation = CAKeyframeAnimation(keyPath: "transform.translation.\(axis.rawValue)")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.duration = 0.6
animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
layer.add(animation, forKey: "shake")
}
func shakeOnXAxis() {
self.shake(on: .x)
}
func shakeOnYAxis() {
self.shake(on: .y)
}
}
@imike answer in Swift 4.2
extension UIView {
func shake() {
let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
animation.duration = 0.6
animation.values = [-20, 20, -20, 20, -10, 10, -5, 5, 0]
self.layer.add(animation, forKey: "shake")
}}