web-dev-qa-db-fra.com

animer UITextField pour indiquer un mot de passe incorrect

comment puis-je ajouter une animation à une UITextField pour indiquer un mot de passe incorrect, exactement comme celui de l'application facebook (à l'écran de connexion) ou de la zone de connexion Mac OS X?

merci d'avance.

28
JAHelia

Quelque chose comme ca

-(void)shake:(UIView *)theOneYouWannaShake
{
  [UIView animateWithDuration:0.03 animations:^
                                  {
                                    theOneYouWannaShake.transform = CGAffineTransformMakeTranslation(5*direction, 0);
                                  } 
                                  completion:^(BOOL finished) 
                                  {
                                    if(shakes >= 10)
                                    {
                                      theOneYouWannaShake.transform = CGAffineTransformIdentity;
                                      return;
                                    }
                                    shakes++;
                                    direction = direction * -1;
                                    [self shake:theOneYouWannaShake];
                                  }];
}

Vous avez donc besoin de trois éléments supplémentaires: une direction int définie sur 1 avant le shake est appelée un int, shake, qui est définie sur 0 avant que le shake ne soit appelé et une constante MAX_SHAKES qui soit aussi grande que vous le souhaitez. J'espère que cela pourra aider.

MODIFIER:

appelez ça comme ça:

  direction = 1;
  shakes = 0;
  [self shake:aUIView];

fichier d'en-tête à l'intérieur ajouter

int direction;
int shakes;
43
Kai Huppmann

(16 janvier 2015) Mise à jour: la conversion (enum UIViewAnimationOptions) est correcte et UIViewAnimationOptionCurveEaseOut est égal à 2 << 16 par UIView.h sous la variable typedef NS_OPTIONS (NSUInteger, UIViewAnimationOptions).

(31 janvier 2013) Nouvelle réponse de Kai modifiée pour inclure:

  1. Retard de bord de 0.01s
  2. easyInOut
  3. réduire la durée des secousses à chaque secousse de 0,09 à 0,04
  4. ralentir le mouvement d'un point toutes les 1 boucle complète (droite-gauche-droite)

Remarque: si vous envisagez de manipuler deux contrôles (email et mot de passe) ensemble, évitez d'utiliser des variables de classe ou statiques pour les shakes et la traduction. Au lieu de cela, initialisez et transmettez shake et traduisez en tant que paramètres. J'ai utilisé la statique, donc pas de variables de classe nécessaires.

-(void)shakeAnimation:(UIView*) view {
    const int reset = 5;
    const int maxShakes = 6;

    //pass these as variables instead of statics or class variables if shaking two controls simultaneously
    static int shakes = 0;
    static int translate = reset;

    [UIView animateWithDuration:0.09-(shakes*.01) // reduce duration every shake from .09 to .04 
                          delay:0.01f//Edge wait delay
                        options:(enum UIViewAnimationOptions) UIViewAnimationCurveEaseInOut
                     animations:^{view.transform = CGAffineTransformMakeTranslation(translate, 0);}
                     completion:^(BOOL finished){
                         if(shakes < maxShakes){
                             shakes++;

                             //throttle down movement
                             if (translate>0)
                                 translate--;

                             //change direction
                             translate*=-1;
                             [self shakeAnimation:view];
                         } else {
                             view.transform = CGAffineTransformIdentity;
                             shakes = 0;//ready for next time
                             translate = reset;//ready for next time
                             return;
                         }
                     }];
}
13
Dickey Singh

Cette réponse Swift 2.0 ne nécessite aucune récursivité ni aucune boucle. Il suffit d’utiliser CABasicAnimation pour préciser cette SO réponse :

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

Mise à jour pour 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")
}
9
Crashalot

Basé sur une réponse précédente en tant que méthode Swift prête à être utilisée:

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

    })

}

Pour l'appeler:

shakeTextField(aTextField,numberOfShakes:0, direction :1, maxShakes : 10)
5
ant_one

Si vous êtes venu ici pour chercher une réponse MonoTouch, voici une traduction approximative de Le code de Dickey :

public static void /*Harlem*/Shake (this UIView view, int shakes = 6, int translation = 5)
{
    UIView.Animate (0.03 + (shakes * 0.01), 0.01, UIViewAnimationOptions.CurveEaseInOut, () => {
        view.Transform = CGAffineTransform.MakeTranslation (translation, 0);
    }, () => {
       if (shakes == 0) {
            view.Transform = CGAffineTransform.MakeIdentity ();
            return;
        }

        if (translation > 0)
            translation --;

        translation *= -1;
        shakes --;

        Shake (view, shakes, translation);
    });
}

Mettez-le avec le reste de vos méthodes d'extensions et appelez comme ça:

password.Shake ();
3
Dan Abramov

Voici mon tour sur elle:

@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
2
Chris

iOS iPhone textbox password window view shaking

J'ai créé une méthode de catégorie pour UIView qui peut être utilisée pour secouer n'importe quel élément - par exemple. UITextField - avec la possibilité d'être averti une fois le tremblement terminé. Voici comment l'utiliser:

[myPasswordField shake];

// Or with a callback after the shake 
[myPasswordField shakeWithCallback:^{
   NSLog(@"Shaking has ended");
}];

Voici le code.

UIView + Shake.h

#import <UIKit/UIKit.h>

@interface UIView (UIView_Shake)

-(void)shake;
-(void)shakeWithCallback:(void (^)(void))completeBlock;

@end

UIView + Shake.m

#import "UIView+Shake.h"
#import <objc/runtime.h>

@implementation UIView (UIView_Shake)

static void *NumCurrentShakesKey;
static void *NumTotalShakesKey;
static void *ShakeDirectionKey;

- (int)numCurrentShakes {
    return [objc_getAssociatedObject(self, &NumCurrentShakesKey) intValue];
}

- (void)setNumCurrentShakes:(int)value {
    objc_setAssociatedObject(self, &NumCurrentShakesKey, [NSNumber numberWithInt:value], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)numTotalShakes {
    return [objc_getAssociatedObject(self, &NumTotalShakesKey) intValue];
}

- (void)setNumTotalShakes:(int)value {
    objc_setAssociatedObject(self, &NumTotalShakesKey, [NSNumber numberWithInt:value], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (int)shakeDirection {
    return [objc_getAssociatedObject(self, &ShakeDirectionKey)  intValue];
}

- (void)setShakeDirection:(int)value {
    objc_setAssociatedObject(self, &ShakeDirectionKey, [NSNumber numberWithInt:value], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(void)shake {
    [self shakeNextWithCompleteBlock:nil];
}

-(void)shakeWithCallback:(void (^)(void))completeBlock {
    self.numCurrentShakes = 0;
    self.numTotalShakes = 6;
    self.shakeDirection = 8;
    [self shakeNextWithCompleteBlock:completeBlock];
}

-(void)shakeNextWithCompleteBlock:(void (^)(void))completeBlock
{
    UIView* viewToShake = self;
    [UIView animateWithDuration:0.08
                     animations:^
     {
         viewToShake.transform = CGAffineTransformMakeTranslation(self.shakeDirection, 0);
     }
                     completion:^(BOOL finished)
     {
         if(self.numCurrentShakes >= self.numTotalShakes)
         {
             viewToShake.transform = CGAffineTransformIdentity;
             if(completeBlock != nil) {
                 completeBlock();
             }
             return;
         }
         self.numCurrentShakes++;
         self.shakeDirection = self.shakeDirection * -1;
         [self shakeNextWithCompleteBlock:completeBlock];
     }];
}

@end
2
Gergely Orosz

J'ai essayé la solution @stefreak mais l'approche en boucle ne fonctionne pas sur iOS 7.1. J'ai donc combiné les solutions de @stefreak et de @Chris, et ajouté le bloc d'achèvement pour être averti lorsque l'agitation est terminée. Voici mon 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];
}
2
boherna

Comme la question portait sur Objective-C et que j'utilise Objective-C dans mon projet, je pense que cette traduction Objective-C de cette réponse précédente de Swift pourrait être utile à quelqu'un d'autre:

- (void)shakeView:(UIView*)view
{
    CABasicAnimation *shake = [CABasicAnimation animationWithKeyPath:@"position"];
    CGFloat xDelta = 5.0;
    shake.duration = 0.15;
    shake.repeatCount = 2;
    shake.autoreverses = YES;

    CGPoint fromPoint = CGPointMake(view.center.x - xDelta, view.center.y);
    CGPoint toPoint = CGPointMake(view.center.x + xDelta, view.center.y);

    shake.fromValue = [NSValue valueWithCGPoint:fromPoint];
    shake.toValue = [NSValue valueWithCGPoint:toPoint];
    shake.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [view.layer addAnimation:shake forKey:@"position"];
}
1
gog

Vous pouvez également le faire en utilisant une animation de base

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

Ici, vous pouvez changer duration, repeatCount. Passer à fromValue et toValue changera la distance parcourue dans la secousse

1
Donal

Il y a une bibliothèque rapide pour animer Textfield dans github ici . Importez simplement le fichier Swift et implémentez-le comme ci-dessous

// 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
0
Rugmangathan

Swift 3 et stackview à la place de textField

func shakeTextField (stack_view : UIStackView, numberOfShakes : Int, direction: CGFloat, maxShakes : Int) {
        let interval : TimeInterval = 0.05

        UIView.animate(withDuration: interval, animations: { () -> Void in
            stack_view.transform = CGAffineTransform(translationX: 5 * direction, y: 0)

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

            if (numberOfShakes >= maxShakes) {
                stack_view.becomeFirstResponder()
                return
            }
            self.shakeTextField(stack_view: stack_view, numberOfShakes: numberOfShakes + 1, direction: direction * -1, maxShakes: maxShakes )
        })
    }
0
Ppillo