web-dev-qa-db-fra.com

Shake Animation pour UITextField/UIView dans Swift

J'essaie de comprendre comment rendre le texte secoué lorsque l'utilisateur laisse le champ vide.

J'ai actuellement le code suivant:

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 {

}

Mais je pense que ce serait beaucoup plus attrayant d'avoir juste le champ de texte secouer comme une alerte.

Je ne trouve rien pour animer le champ de texte.

Des idées?

Merci!

50
Joe CRONE Scrivens

Vous pouvez modifier duration et repeatCount et le modifier. C'est ce que j'utilise dans mon code. La variation de fromValue et toValue fera varier la distance parcourue pendant le tremblement.

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

La fonction suivante est utilisée dans n'importe quelle vue.

extension UIView {
    func shake() {
        let animation = CAKeyframeAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        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")
    }
}
109
Surckarter

Ou vous pouvez l'utiliser si vous voulez plus de paramètres ( dans Swift 3 et Swift 4 ):

public extension UIView {

    func shake(count : Float = 4,for duration : TimeInterval = 0.5,withTranslation translation : Float = 5) {

        let animation : CABasicAnimation = CABasicAnimation(keyPath: "transform.translation.x")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.repeatCount = count
        animation.duration = duration/TimeInterval(animation.repeatCount)
        animation.autoreverses = true
        animation.fromValue = NSValue(cgPoint: CGPoint(x: -translation, y: self.center.y))
        animation.toValue = NSValue(cgPoint: CGPoint(x: translation, y: self.center.y))
        layer.add(animation, forKey: "shake")
    }  
}

Vous pouvez appeler cette fonction sur n’importe quel UIView, UIButton, UILabel, UITextView, etc. De cette façon

yourView.shake()

Ou de cette manière si vous souhaitez ajouter des paramètres personnalisés à l'animation:

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

Je pense que tout cela est dangereux. 

Si votre animation est basée sur une action de l'utilisateur et que cette action est déclenchée pendant l'animation. 

CRAAAAAASH

Voici mon chemin dans 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()
}

Peut-être pas la plus propre, mais cette méthode peut être déclenchée à plusieurs reprises et est facilement comprise

Modifier:

Je suis un grand partisan de l'utilisation de UIViewPropertyAnimator. Autant de fonctionnalités intéressantes vous permettant d'apporter des modifications dynamiques aux animations de base.

Voici un autre exemple permettant d’ajouter une bordure rouge lorsque la vue est agitée, puis de la supprimer une fois l’agitation terminée.

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()
}
18
Corey Pett

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

Utiliser

self.vwOffer.shake()
9
Hardik Thakkar
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)
    }
}

Comment utiliser:

[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])

}

// écrit dans la classe de base ou n'importe quel contrôleur de vue et l'utilise

1
Rana Ali Waseem

Ceci est basé sur CABasicAnimation, il contient également un effet 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..")
        }
    }
}
0