ios Swift 中 UITextField/UIView 的抖动动画
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27987048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shake Animation for UITextField/UIView in Swift
提问by Joe CRONE Scrivens
I am trying to figure out how to make the text Field shake on button press when the user leaves the text field blank.
我试图弄清楚当用户将文本字段留空时,如何使文本字段在按下按钮时震动。
I currently have the following code working:
我目前有以下代码工作:
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 appealing to just have the text field shake as an alert.
但我认为将文本字段作为警报摇晃会更有吸引力。
I can't find anything to animate the text field.
我找不到任何可以为文本字段设置动画的内容。
Any ideas?
有任何想法吗?
Thanks!
谢谢!
回答by rakeshbs
You can change the duration
and repeatCount
and tweak it. This is what I use in my code. Varying the fromValue
and toValue
will vary the distance moved in the shake.
您可以更改duration
和repeatCount
并调整它。这是我在我的代码中使用的。改变fromValue
和toValue
将改变震动中移动的距离。
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")
回答by Surckarter
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")
}
}
回答by RomOne
EDIT: using CABasicAnimation
cause the app to crash if you ever trigger the animation twice in a row. So be sure to use CAKeyframeAnimation
. Bug has been fixed, thanks to the comments :)
编辑:CABasicAnimation
如果您连续两次触发动画,则使用会导致应用程序崩溃。所以一定要使用CAKeyframeAnimation
. 错误已修复,感谢评论:)
Or you can use this if you want more parameters (in swift 5) :
或者,如果您想要更多参数(在 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. This way
你可以在任何 UIView、UIButton、UILabel、UITextView 等上调用这个函数。这样
yourView.shake()
Or this way if you want to add some custom parameters to the animation:
或者,如果您想向动画添加一些自定义参数,请使用这种方式:
yourView.shake(count: 5, for: 1.5, withTranslation: 10)
回答by Corey Pett
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
CRAAAAASH
Here is my way in Swift 4:
这是我在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.
我非常支持使用 UIViewPropertyAnimator。这么多很酷的功能,让您可以对基本动画进行动态修改。
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()
}
回答by Hardik Thakkar
Swift 5.0
斯威夫特 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")
}
}
To use
使用
self.vwOffer.shake()
回答by Dmitriiy Mitrophanskiy
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))
回答by Vahid
Swift 5
斯威夫特 5
Safe (non crash) shake extension for Corey Pett
answer:
安全(非崩溃)震动扩展以获取Corey Pett
答案:
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()
}
}
回答by ricardopereira
I tried some of the available solutions but none of them was handling the full shakeanimation: moving from left to right and get back to the original position.
我尝试了一些可用的解决方案,但没有一个能够处理完全震动的动画:从左向右移动并回到原始位置。
So, after some investigation I found the right solution that I consider to be a successful shake using UIViewPropertyAnimator
.
因此,经过一番调查,我找到了正确的解决方案,我认为使用UIViewPropertyAnimator
.
func shake(completion: (() -> Void)? = nil) {
let speed = 0.75
let time = 1.0 * speed - 0.15
let timeFactor = CGFloat(time / 4)
let animationDelays = [timeFactor, timeFactor * 2, timeFactor * 3]
let shakeAnimator = UIViewPropertyAnimator(duration: time, dampingRatio: 0.3)
// left, right, left, center
shakeAnimator.addAnimations({
self.transform = CGAffineTransform(translationX: 20, y: 0)
})
shakeAnimator.addAnimations({
self.transform = CGAffineTransform(translationX: -20, y: 0)
}, delayFactor: animationDelays[0])
shakeAnimator.addAnimations({
self.transform = CGAffineTransform(translationX: 20, y: 0)
}, delayFactor: animationDelays[1])
shakeAnimator.addAnimations({
self.transform = CGAffineTransform(translationX: 0, y: 0)
}, delayFactor: animationDelays[2])
shakeAnimator.startAnimation()
shakeAnimator.addCompletion { _ in
completion?()
}
shakeAnimator.startAnimation()
}
Final result:
最后结果:
回答by Rana Ali Waseem
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 base class or any view controller and use it
//写入基类或任何视图控制器并使用它
回答by Alessandro Ornano
This is based on CABasicAnimation, it contain also an audio effect :
这是基于 CABasicAnimation,它还包含一个音频效果:
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..")
}
}
}