Shake visual effect on iPhone (NOT shaking the device)

后端 未结 11 751
忘了有多久
忘了有多久 2020-12-02 05:06

On login failure, I\'d prefer to avoid showing an alert, it\'s too fleeting. Showing the alert and then showing the text somewhere on the login screen seems like duplication

相关标签:
11条回答
  • 2020-12-02 05:33

    I know the question is already answered, but since I have already implemented something like this previously, I feel it can't hurt to add it:

    CAKeyframeAnimation *shakeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
    NSArray *transformValues = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat:((M_PI)/64)],
                            [NSNumber numberWithFloat:(-((M_PI)/64))],
                            [NSNumber numberWithFloat:((M_PI)/64)],
                            [NSNumber numberWithFloat:(-((M_PI)/64))],
                            [NSNumber numberWithFloat:((M_PI)/64)],
                            [NSNumber numberWithFloat:(-((M_PI)/64))],
                            [NSNumber numberWithFloat:0],                                
                            nil];
    
    [shakeAnimation setValues:transformValues];
    
    NSArray *times = [NSArray arrayWithObjects:
                      [NSNumber numberWithFloat:0.14f],
                      [NSNumber numberWithFloat:0.28f],
                      [NSNumber numberWithFloat:0.42f],
                      [NSNumber numberWithFloat:0.57f],
                      [NSNumber numberWithFloat:0.71f],
                      [NSNumber numberWithFloat:0.85f],
                      [NSNumber numberWithFloat:1.0f], 
                      nil];
    
    [shakeAnimation setKeyTimes:times];
    
    shakeAnimation.fillMode = kCAFillModeForwards;
    shakeAnimation.removedOnCompletion = NO;
    shakeAnimation.duration = 0.6f;
    
    [self.viewToShake.layer addAnimation:shakeAnimation forKey:@"anim"];
    

    Also, since you want the shaking to indicate that the user failed to log in, you might also consider adding this animation that tints the screen red while the screen shakes:

    //Put this in the header (.h)
    @property (nonatomic, strong) UIView *redView;
    
    //Put this in the implementation (.m)
    @synthesize redView;
    
    //Put this in viewDidLoad
    self.redView = [[UIView alloc] initWithFrame:self.view.frame];
    self.redView.layer.opacity = 0.0f;
    self.redView.layer.backgroundColor = [[UIColor redColor] CGColor];
    
    //Put this wherever you check if the login failed
    CAKeyframeAnimation *redTint = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
    NSArray *transformValues = [NSArray arrayWithObjects:
                               [NSNumber numberWithFloat:0.2f],
                               [NSNumber numberWithFloat:0.0f],                                
                               nil];
    
    [redTint setValues:transformValues];
    
    NSArray *times = [NSArray arrayWithObjects:
                      [NSNumber numberWithFloat:0.5f],
                      [NSNumber numberWithFloat:1.0f], 
                      nil];
    
    [redTint setKeyTimes:times];
    
    redTint.fillMode = kCAFillModeForwards;
    redTint.removedOnCompletion = NO;
    redTint.duration = 0.6f;
    
    [self.redView.layer addAnimation:shakeAnimation forKey:@"anim"];
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-02 05:41

    Here's a tutorial that details how to do it in Cocoa. Should be the same for the iPhone (or at least quite similar).

    http://www.cimgf.com/2008/02/27/core-animation-tutorial-window-shake-effect/

    0 讨论(0)
  • 2020-12-02 05:42

    very easy shake categorie for UIVoew

    https://github.com/jonasschnelli/UIView-I7ShakeAnimation

    0 讨论(0)
  • 2020-12-02 05:43

    This UIView category snippet worked for me. It's using 3 CABasingAnimations applied to view's layer.

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>
    
    #define Y_OFFSET 2.0f
    #define X_OFFSET 2.0f
    #define ANGLE_OFFSET (M_PI_4*0.1f)
    
    @interface UIView (shakeAnimation)
    
    -(BOOL)isShakeAnimationRunning;
    -(void)startShakeAnimation;
    -(void)stopShakeAnimation;
    
    @end
    
    
    
    @implementation UIView (shakeAnimation)
    
    -(BOOL)isShakeAnimationRunning{
         return [self.layer animationForKey:@"shake_rotation"] != nil;
    }
    
    -(void)startShakeAnimation{
        CFTimeInterval offset=(double)arc4random()/(double)RAND_MAX;
        self.transform=CGAffineTransformRotate(self.transform, -ANGLE_OFFSET*0.5);
        self.transform=CGAffineTransformTranslate(self.transform, -X_OFFSET*0.5f, -Y_OFFSET*0.5f);
    
        CABasicAnimation *tAnim=[CABasicAnimation animationWithKeyPath:@"position.x"];
        tAnim.repeatCount=HUGE_VALF;
        tAnim.byValue=[NSNumber numberWithFloat:X_OFFSET];
        tAnim.duration=0.07f;
        tAnim.autoreverses=YES;
        tAnim.timeOffset=offset;
        [self.layer addAnimation:tAnim forKey:@"shake_translation_x"];
    
        CABasicAnimation *tyAnim=[CABasicAnimation animationWithKeyPath:@"position.y"];
        tyAnim.repeatCount=HUGE_VALF;
        tyAnim.byValue=[NSNumber numberWithFloat:Y_OFFSET];
        tyAnim.duration=0.06f;
        tyAnim.autoreverses=YES;
        tyAnim.timeOffset=offset;
        [self.layer addAnimation:tyAnim forKey:@"shake_translation_y"];
    
        CABasicAnimation *rAnim=[CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        rAnim.repeatCount=HUGE_VALF;
        rAnim.byValue=[NSNumber numberWithFloat:ANGLE_OFFSET];
        rAnim.duration=0.15f;
        rAnim.autoreverses=YES;
        rAnim.timeOffset=offset;
        [self.layer addAnimation:rAnim forKey:@"shake_rotation"];
    }
    -(void)stopShakeAnimation{
        [self.layer removeAnimationForKey:@"shake_translation_x"];
        [self.layer removeAnimationForKey:@"shake_translation_y"];
        [self.layer removeAnimationForKey:@"shake_rotation"];
        [UIView animateWithDuration:0.2f animations:^{
            self.transform=CGAffineTransformRotate(self.transform, ANGLE_OFFSET*0.5);
            self.transform=CGAffineTransformTranslate(self.transform, X_OFFSET*0.5, Y_OFFSET*0.5f);
        }];
    }
    
    @end
    

    Hope it helpes someone :)

    0 讨论(0)
  • 2020-12-02 05:46

    I had seen some wobble animation and changed it to shake a view t pixels upright and downleft:

    - (void)earthquake:(UIView*)itemView
    {
        CGFloat t = 2.0;
    
        CGAffineTransform leftQuake  = CGAffineTransformTranslate(CGAffineTransformIdentity, t, -t);
        CGAffineTransform rightQuake = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, t);
    
        itemView.transform = leftQuake;  // starting point
    
        [UIView beginAnimations:@"earthquake" context:itemView];
        [UIView setAnimationRepeatAutoreverses:YES]; // important
        [UIView setAnimationRepeatCount:5];
        [UIView setAnimationDuration:0.07];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(earthquakeEnded:finished:context:)];
    
        itemView.transform = rightQuake; // end here & auto-reverse
    
        [UIView commitAnimations];
    }
    
    - (void)earthquakeEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context 
    {
        if ([finished boolValue]) 
        {
            UIView* item = (UIView *)context;
            item.transform = CGAffineTransformIdentity;
        }
    }
    
    0 讨论(0)
提交回复
热议问题