ios swift uitextfield

text field ios 11



Shake Animation para UITextField/UIView en Swift (10)

Estoy tratando de descubrir cómo hacer que el campo de texto se agite al presionar el botón cuando el usuario deja el campo de texto en blanco.

Actualmente tengo el siguiente código funcionando:

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 { }

Pero creo que sería mucho más atractivo que el campo de texto se sacudiera como alerta.

No puedo encontrar nada para animar el campo de texto.

¿Algunas ideas?

¡Gracias!


Creo que todo esto es peligroso.

Si su animación de agitación se basa en una acción del usuario y esa acción del usuario se activa durante la animación.

CRAAAAAASH

Aquí está mi camino en 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() }

Tal vez no sea el más limpio, pero este método se puede activar repetidamente y se entiende fácilmente

Editar:

Soy un gran defensor del uso de UIViewPropertyAnimator. Tantas funciones interesantes que le permiten realizar modificaciones dinámicas en animaciones básicas.

Aquí hay otro ejemplo para agregar un borde rojo mientras la vista está temblando, y luego eliminarlo cuando finalice el movimiento.

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() }


EDITAR: el uso de CABasicAnimation hace que la aplicación se bloquee si alguna vez activa la animación dos veces seguidas. Así que asegúrese de usar CAKeyframeAnimation . Se ha solucionado el error, gracias a los comentarios :)

O puede usar esto si desea más parámetros ( en 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") } }

Puede llamar a esta función en cualquier UIView, UIButton, UILabel, UITextView, etc. De esta manera

yourView.shake()

O de esta manera si desea agregar algunos parámetros personalizados a la animación:

yourView.shake(count: 5, for: 1.5, withTranslation: 10)


Esto se basa en CABasicAnimation, contiene también un efecto de audio:

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..") } } }


La siguiente función se utiliza en cualquier vista.

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") } }


Probé algunas de las soluciones disponibles, pero ninguna de ellas estaba manejando la animación de movimiento completo : moviéndome de izquierda a derecha y volviendo a la posición original.

Entonces, después de una investigación, encontré la solución correcta que considero un batido exitoso usando 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() }

Resultado final:


Puede cambiar la duration y repeatCount y repeatCount . Esto es lo que uso en mi código. Variar fromValue y toValue variará la distancia recorrida en el batido.

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")


Swift 5

Extensión de sacudida segura (sin bloqueo) para Corey Pett respuesta:

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() } }


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") } }

Usar

self.vwOffer.shake()


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) } }

Cómo utilizar:

[UIView, UILabel, UITextField, UIButton & etc].layer.shake(NSTimeInterval(0.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]) }

// escribe en la clase base o cualquier controlador de vista y úsalo