Shake Animation для UITextField/UIView в Swift
Я пытаюсь понять, как сделать текст Поле дрожит при нажатии кнопки, когда пользователь оставляет текстовое поле пустым.
В настоящее время у меня работает следующий код:
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 {
}
Но я думаю, что было бы гораздо более привлекательно просто вставлять текстовое поле в качестве предупреждения.
Я ничего не могу найти для анимации текстового поля.
Любые идеи?
Спасибо!
Ответы
Ответ 1
Вы можете изменить 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")
Ответ 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.0, 20.0, -20.0, 20.0, -10.0, 10.0, -5.0, 5.0, 0.0 ]
layer.add(animation, forKey: "shake")
}
}
Ответ 3
РЕДАКТИРОВАТЬ: использование CABasicAnimation
вызывает CABasicAnimation
приложения, если вы когда-либо запускаете анимацию дважды подряд. Поэтому обязательно используйте CAKeyframeAnimation
. Исправлена ошибка, благодаря комментариям :)
Или вы можете использовать это, если вы хотите больше параметров (в 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")
}
}
Вы можете вызвать эту функцию на любом UIView, UIButton, UILabel, UITextView и т.д. Таким образом
yourView.shake()
Или так, если вы хотите добавить некоторые пользовательские параметры для анимации:
yourView.shake(count: 5, for: 1.5, withTranslation: 10)
Ответ 4
Я думаю, что все это опасно.
Если ваша анимация встряски основана на действии пользователя и что действие пользователя запускается во время анимации.
CRAAAAAASH
Вот мой путь в 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()
}
Может быть, не самый чистый, но этот метод можно запускать многократно и легко понять
Редактировать:
Я большой сторонник использования UIViewPropertyAnimator. Так много интересных функций, которые позволяют вам делать динамические изменения в основных анимациях.
Вот еще один пример, чтобы добавить красную рамку, пока вид трясет, а затем удаляет ее, когда встряска заканчивается.
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()
}
Ответ 5
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")
}
}
Использовать
self.vwOffer.shake()
Ответ 6
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)
}
}
Как использовать:
[UIView, UILabel, UITextField, UIButton & etc].layer.shake(NSTimeInterval(0.7))
Ответ 7
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])
}
//писать в базовом классе или любом контроллере представления и использовать его
Ответ 8
Это основано на 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..")
}
}
}
Ответ 9
Swift 5
Расширение безопасного (без сбоев) встряхивания для ответа 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()
}
}
Ответ 10
Я попробовал некоторые из доступных решений, но ни одно из них не обрабатывало анимацию полного встряхивания: перемещался слева направо и возвращался в исходное положение.
Итак, после некоторого расследования я нашел правильное решение, которое я считаю удачным, используя 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()
}
Окончательный результат:
![shake-animation-result]()