Shake visual effect on iPhone (NOT shaking the dev

2019-01-10 00:57发布

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?

11条回答
Juvenile、少年°
2楼-- · 2019-01-10 01:30

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!

查看更多
我欲成王,谁敢阻挡
3楼-- · 2019-01-10 01:33

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;
    }
}
查看更多
放荡不羁爱自由
4楼-- · 2019-01-10 01:34

A solution I used for constraints which I set in my storyboard. Without using animateWithDuration.

@IBOutlet var balloonHorizontalConstraint: NSLayoutConstraint!

NSTimer.scheduledTimerWithTimeInterval(0.04, target: self, selector: "animateBalloon", userInfo: nil, repeats: true)

func animateBalloon() {
    switch balloonHorizontalConstraint.constant {
    case -46:
        balloonHorizontalConstraint.constant = -50
    default:
        balloonHorizontalConstraint.constant = -46
    }
}

In my case the animation just kept on going, but I pop my viewcontroller after a duration of a few seconds, this stops my timer aswell.

查看更多
家丑人穷心不美
5楼-- · 2019-01-10 01:35

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];
        }
    }];
}
查看更多
欢心
6楼-- · 2019-01-10 01:38

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/

查看更多
登录 后发表回答