animating UITextField to indicate a wrong password

2019-01-30 11:45发布

how can I add an animation to a UITextField to indicate wrong password exactly like the one in facebook app (at login screen) or the Mac OS X login box ?

thank you in advance.

12条回答
Melony?
2楼-- · 2019-01-30 12:25

You can also do it using basic animation

let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.09
animation.repeatCount = 4
animation.autoreverses = true
animation.fromValue = NSValue(CGPoint: CGPointMake(txtField.center.x - 10, txtField.center.y))
animation.toValue = NSValue(CGPoint: CGPointMake(txtField.center.x + 10, txtField.center.y))
txtField.layer.addAnimation(animation, forKey: "position")

Here you can the change duration,repeatCount.Changing into the fromValue and toValue will change distance moved in the shake

查看更多
小情绪 Triste *
3楼-- · 2019-01-30 12:30

There's a Swift Library for animating Textfield in github here. Simply import the swift file and implement as below

// Shake with the default speed
self.textField.shake(10, delta:5) //10 no. of shakes with 5 points wide

// Shake with a custom speed
self.sampleText.shake(10, delta: 5, speed: 0.10) //10 no. of shakes with 5 points wide in 100ms per shake
查看更多
狗以群分
4楼-- · 2019-01-30 12:31

Based on a previous answer as swift method ready to use :

func shakeTextField (textField : UITextField, numberOfShakes : Int, direction: CGFloat, maxShakes : Int) {

    let interval : NSTimeInterval = 0.03

    UIView.animateWithDuration(interval, animations: { () -> Void in
        textField.transform = CGAffineTransformMakeTranslation(5 * direction, 0)

        }, completion: { (aBool :Bool) -> Void in

            if (numberOfShakes >= maxShakes) {
                textField.transform = CGAffineTransformIdentity
                textField.becomeFirstResponder()
                return
            }

            self.shakeTextField(textField, numberOfShakes: numberOfShakes + 1, direction: direction * -1, maxShakes: )

    })

}

To call it :

shakeTextField(aTextField,numberOfShakes:0, direction :1, maxShakes : 10)
查看更多
可以哭但决不认输i
5楼-- · 2019-01-30 12:32

This Swift 2.0 answer requires no recursion and no loops. Just leverages CABasicAnimation by refining this SO answer:

func shakeView(shakeView: UIView) {
    let shake = CABasicAnimation(keyPath: "position")
    let xDelta = CGFloat(5)
    shake.duration = 0.15
    shake.repeatCount = 2
    shake.autoreverses = true

    let from_point = CGPointMake(shakeView.center.x - xDelta, shakeView.center.y)
    let from_value = NSValue(CGPoint: from_point)

    let to_point = CGPointMake(shakeView.center.x + xDelta, shakeView.center.y)
    let to_value = NSValue(CGPoint: to_point)

    shake.fromValue = from_value
    shake.toValue = to_value
    shake.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    shakeView.layer.addAnimation(shake, forKey: "position")
}

Updated for Swift 4:

func shakeView(_ shakeView: UIView) {
    let shake = CABasicAnimation(keyPath: "position")
    let xDelta = CGFloat(5)
    shake.duration = 0.15
    shake.repeatCount = 2
    shake.autoreverses = true

    let from_point = CGPoint(x: shakeView.center.x - xDelta, y: shakeView.center.y)
    let from_value = NSValue(cgPoint: from_point)

    let to_point = CGPoint(x: shakeView.center.x + xDelta, y: shakeView.center.y)
    let to_value = NSValue(cgPoint: to_point)

    shake.fromValue = from_value
    shake.toValue = to_value
    shake.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    shakeView.layer.add(shake, forKey: "position")
}
查看更多
我想做一个坏孩纸
6楼-- · 2019-01-30 12:32

I tried @stefreak solution but the loop approach doesn't work on iOS 7.1. So I combined the solutions from @stefreak and @Chris, and added the completion block to be notified when the shaking finishes. Here is my code:

- (void)shakeView:(UIView *)view iterations:(NSInteger)iterations direction:(NSInteger)direction completion:(void (^)())completion
{
    const NSInteger MAX_SHAKES = 6;
    const CGFloat SHAKE_DURATION = 0.05;
    const CGFloat SHAKE_TRANSFORM = 10.0;

    [UIView animateWithDuration:SHAKE_DURATION
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseIn
                     animations:^{
                         view.transform = iterations >= MAX_SHAKES ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(SHAKE_TRANSFORM * direction, 0);
                     } completion:^(BOOL finished) {
                         if (finished)
                         {
                             if (iterations >= MAX_SHAKES)
                             {
                                 if (completion)
                                 {
                                     completion();
                                 }
                             }
                             else
                             {
                                 [self shakeView:view iterations:(iterations + 1) direction:(direction * -1) completion:completion];
                             }
                         }
                     }];
}

- (void)shakeView:(UIView *)view completion:(void (^)())completion
{
    [self shakeView:view iterations:0 direction:1 completion:completion];
}
查看更多
女痞
7楼-- · 2019-01-30 12:34

Here's my spin on it:

@implementation UITextField (Shake)

- (void)shake {
    [self shakeWithIterations:0 direction:1 size:4];
}

#pragma mark - Private

- (void)shakeWithIterations:(int)iterations direction:(int)direction size:(int)size {
    [UIView animateWithDuration:0.09-(iterations*.01) animations:^{
        self.transform = CGAffineTransformMakeTranslation(size*direction, 0);
    } completion:^(BOOL finished) {
        if (iterations >= 5 || size <= 0) {
            self.transform = CGAffineTransformIdentity;
            return;
        }
        [self shakeWithIterations:iterations+1 direction:direction*-1 size:MAX(0, size-1)];
    }];
}

@end
查看更多
登录 后发表回答