Question

Shake visual effect on iPhone (NOT shaking the device)

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.

So I'd like for it to graphically shake my login view when the user enters the wrong user ID and password like the Mac login screen does.

Anyone know if there's a way to pull this off, or have any suggestions for another effect I could use?

 45  21145  45
1 Jan 1970

Solution

 98

I think this is a more efficient solution:

Swift:

let anim = CAKeyframeAnimation( keyPath:"transform" )
anim.values = [
    NSValue( CATransform3D:CATransform3DMakeTranslation(-5, 0, 0 ) ),
    NSValue( CATransform3D:CATransform3DMakeTranslation( 5, 0, 0 ) )
]
anim.autoreverses = true
anim.repeatCount = 2
anim.duration = 7/100

viewToShake.layer.addAnimation( anim, forKey:nil )

Obj-C:

CAKeyframeAnimation * anim = [ CAKeyframeAnimation animationWithKeyPath:@"transform" ] ;
anim.values = @[ 
    [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-5.0f, 0.0f, 0.0f) ], 
    [ NSValue valueWithCATransform3D:CATransform3DMakeTranslation( 5.0f, 0.0f, 0.0f) ] 
] ;
anim.autoreverses = YES ;
anim.repeatCount = 2.0f ;
anim.duration = 0.07f ;

[ viewToShake.layer addAnimation:anim forKey:nil ] ;

Only one animation object is created and it's all performed at the CoreAnimation level.

2012-02-21

Solution

 58

Using iOS 4+ block based UIKit animations (and loosely based on on jayccrown's answer):

- (void)shakeView:(UIView *)viewToShake
{
    CGFloat t = 2.0;
    CGAffineTransform translateRight  = CGAffineTransformTranslate(CGAffineTransformIdentity, t, 0.0);
    CGAffineTransform translateLeft = CGAffineTransformTranslate(CGAffineTransformIdentity, -t, 0.0);

    viewToShake.transform = translateLeft;

    [UIView animateWithDuration:0.07 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
        [UIView setAnimationRepeatCount:2.0];
        viewToShake.transform = translateRight;
    } completion:^(BOOL finished) {
        if (finished) {
            [UIView animateWithDuration:0.05 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
                viewToShake.transform = CGAffineTransformIdentity;
            } completion:NULL];
        }
    }];
}
2011-05-11