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