I think all of these are dangerous.
If your shake animation is based on a user action and that user action is triggered while animating.
CRAAAAAASH
Here is my way 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()
}
Maybe not the cleanest, but this method can be triggered repeatedly and is easily understood
Edit:
I am a huge proponent for usage of UIViewPropertyAnimator. So many cool features that allow you to make dynamic modifications to basic animations.
Here is another example to add a red border while the view is shaking, then removing it when the shake finishes.
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()
}