Shake Animation for UITextField / UIView in Swift

I'm trying to figure out how to make text. The field is shaking when the button is clicked, when the user leaves the text field blank.

Currently the following code is working for me:

if self.subTotalAmountData.text == "" { let alertController = UIAlertController(title: "Title", message: "What is the Sub-Total!", preferredStyle: UIAlertControllerStyle.Alert) alertController.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default,handler: nil)) self.presentViewController(alertController, animated: true, completion: nil) } else { } 

But I think it would be much more attractive to just insert a text box as a warning.

I can't find anything to animate a text box.

Any ideas?

Thank!

+58
ios uitextfield swift
Jan 16 '15 at 15:15
source share
9 answers

You can change duration and repeatCount and adjust it. This is what I use in my code. Changing the fromValue and toValue will vary the distance moved in the jitter.

 let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.07 animation.repeatCount = 4 animation.autoreverses = true animation.fromValue = NSValue(cgPoint: CGPoint(x: viewToShake.center.x - 10, y: viewToShake.center.y)) animation.toValue = NSValue(cgPoint: CGPoint(x: viewToShake.center.x + 10, y: viewToShake.center.y)) viewToShake.layer.add(animation, forKey: "position") 
+135
Jan 16 '15 at 16:53
source share

The following function is used in any view.

 extension UIView { func shake() { let animation = CAKeyframeAnimation(keyPath: "transform.translation.x") animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) animation.duration = 0.6 animation.values = [-20.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ] layer.add(animation, forKey: "shake") } } 
+128
Jan 13 '16 at 22:39
source share

EDIT: using CABasicAnimation calls the application's CABasicAnimation if you ever run the animation twice in a row. Therefore, be sure to use CAKeyframeAnimation . Bug fixed thanks to comments :)




Or you can use this if you want more options ( in Swift 5 ):

 public extension UIView { func shake(count : Float = 4,for duration : TimeInterval = 0.5,withTranslation translation : Float = 5) { let animation = CAKeyframeAnimation(keyPath: "transform.translation.x") animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) animation.repeatCount = count animation.duration = duration/TimeInterval(animation.repeatCount) animation.autoreverses = true animation.values = [translation, -translation] layer.add(animation, forKey: "shake") } } 

You can call this function on any UIView, UIButton, UILabel, UITextView, etc. In this way

 yourView.shake() 

Or so if you want to add some custom options for the animation:

 yourView.shake(count: 5, for: 1.5, withTranslation: 10) 
+38
Aug 05 '16 at 13:11
source share

I think all this is dangerous.

If your shake animation is based on user action and that user action is triggered during the animation.

CRAAAAAASH

Here is my path in Swift 4 :

 static func shake(view: UIView, for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) { let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) { view.transform = CGAffineTransform(translationX: translation, y: 0) } propertyAnimator.addAnimations({ view.transform = CGAffineTransform(translationX: 0, y: 0) }, delayFactor: 0.2) propertyAnimator.startAnimation() } 

It may not be the cleanest, but this method can be run multiple times and is easy to understand

Edit:

I am a big proponent of using UIViewPropertyAnimator. So many interesting features that allow you to make dynamic changes to the main animations.

Here is another example to add a red border until the view shakes and then removes it when the shake ends.

 static func shake(view: UIView, for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) { let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) { view.layer.borderColor = UIColor.red.cgColor view.layer.borderWidth = 1 view.transform = CGAffineTransform(translationX: translation, y: 0) } propertyAnimator.addAnimations({ view.transform = CGAffineTransform(translationX: 0, y: 0) }, delayFactor: 0.2) propertyAnimator.addCompletion { (_) in view.layer.borderWidth = 0 } propertyAnimator.startAnimation() } 
+22
Apr 28 '18 at 18:54
source share

Swift 5.0

 extension UIView { func shake(){ let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.07 animation.repeatCount = 3 animation.autoreverses = true animation.fromValue = NSValue(cgPoint: CGPoint(x: self.center.x - 10, y: self.center.y)) animation.toValue = NSValue(cgPoint: CGPoint(x: self.center.x + 10, y: self.center.y)) self.layer.add(animation, forKey: "position") } } 

Use

 self.vwOffer.shake() 
+10
Sep 02 '17 at 10:42 on
source share
 extension CALayer { func shake(duration: NSTimeInterval = NSTimeInterval(0.5)) { let animationKey = "shake" removeAnimationForKey(animationKey) let kAnimation = CAKeyframeAnimation(keyPath: "transform.translation.x") kAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) kAnimation.duration = duration var needOffset = CGRectGetWidth(frame) * 0.15, values = [CGFloat]() let minOffset = needOffset * 0.1 repeat { values.append(-needOffset) values.append(needOffset) needOffset *= 0.5 } while needOffset > minOffset values.append(0) kAnimation.values = values addAnimation(kAnimation, forKey: animationKey) } } 

How to use:

 [UIView, UILabel, UITextField, UIButton & etc].layer.shake(NSTimeInterval(0.7)) 
+3
May 26 '16 at 14:24
source share
 func shakeTextField(textField: UITextField) { let animation = CABasicAnimation(keyPath: "position") animation.duration = 0.07 animation.repeatCount = 3 animation.autoreverses = true animation.fromValue = NSValue(cgPoint: CGPoint(x: textField.center.x - 10, y: textField.center.y)) animation.toValue = NSValue(cgPoint: CGPoint(x: textField.center.x + 10, y: textField.center.y)) textField.layer.add(animation, forKey: "position") textField.attributedPlaceholder = NSAttributedString(string: textField.placeholder ?? "", attributes: [NSAttributedStringKey.foregroundColor: UIColor.red]) } 

// write in the base class or any view controller and use it

+1
Nov 13 '18 at 12:32
source share

It is based on CABasicAnimation, it also contains a sound effect:

 extension UIView{ var audioPlayer = AVAudioPlayer() 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 - 5.0, self.center.y)) animation.toValue = NSValue(CGPoint: CGPointMake(self.center.x + 5.0, self.center.y)) self.layer.addAnimation(animation, forKey: "position") // audio part do { audioPlayer = try AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(mySoundFileName, ofType: "mp3")!)) audioPlayer.prepareToPlay() audioPlayer.play() } catch { print("∙ Error playing vibrate sound..") } } } 
0
Jun 09 '16 at 13:56 on
source share

Swift 5

Extending safe (no crashing) shaking for Corey Pett answer:

 extension UIView { func shake(for duration: TimeInterval = 0.5, withTranslation translation: CGFloat = 10) { let propertyAnimator = UIViewPropertyAnimator(duration: duration, dampingRatio: 0.3) { self.transform = CGAffineTransform(translationX: translation, y: 0) } propertyAnimator.addAnimations({ self.transform = CGAffineTransform(translationX: 0, y: 0) }, delayFactor: 0.2) propertyAnimator.startAnimation() } } 
0
Sep 03 '19 at 10:45
source share



All Articles