Shake visual effect on iPhone (NOT shaking the device)

后端 未结 11 750
忘了有多久
忘了有多久 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:22

    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];
            }
        }];
    }
    
    0 讨论(0)
  • 2020-12-02 05:22

    Simply changing the X coordinate of the center property of your view might do the trick. If you haven't done any core animation before it's pretty straight-forward.

    First, start an animation right, then listen for it to finish, and then move back to the left, and so on. Getting the timing down so it "feels right" might take a while.

    - (void)animationFinishCallback:(NSString *)animationID finished:(BOOL)finished context:(void *)context
    {
      if ([animationID isEqualToString:@"MoveRight"]) {
        [UIView beginAnimations:@"MoveLeft" context:NULL];
        [UIView setAnimationDuration:1.0];
        [UIView setAnimationDelay: UIViewAnimationCurveEaseIn];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animationFinishCallback:finished:context:)];
    
        myView.center = CGRectMake(newX, newY);
        [UIView commitAnimations];
      }
    }
    
    0 讨论(0)
  • 2020-12-02 05:25

    Using Auto Layout, I adapted Chris Miles' answer but animated NSLayoutConstraints like this:

    NSLayoutConstraint *left  = ...
    NSLayoutConstraint *right = ...
    
    [UIView animateWithDuration:0.08 delay:0.0 options:UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
        [UIView setAnimationRepeatCount:3];
        left.constant  = 15.0;
        right.constant = 25.0;
        [self.view layoutIfNeeded];
    } completion:^(BOOL finished) {
        if (finished) {
            [UIView animateWithDuration:0.08 animations:^{
                left.constant  = 20.0;
                right.constant = 20.0;
                [self.view layoutIfNeeded];
            } completion:NULL];
        }
    }];
    
    0 讨论(0)
  • 2020-12-02 05:28

    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.

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

    In iOS 7.0 or later, UIKit keyframe animation is available.

    [UIView animateKeyframesWithDuration:0.5 delay:0.0 options:0 animations:^{
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    
        NSInteger repeatCount = 8;
        NSTimeInterval duration = 1.0 / (NSTimeInterval)repeatCount;
    
        for (NSInteger i = 0; i < repeatCount; i++) {
            [UIView addKeyframeWithRelativeStartTime:i * duration relativeDuration:duration animations:^{
                CGFloat dx = 5.0;
                if (i == repeatCount - 1) {
                    viewToShake.transform = CGAffineTransformIdentity;
                } else if (i % 2) {
                    viewToShake.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, -dx, 0.0);
                } else {
                    viewToShake.transform = CGAffineTransformTranslate(CGAffineTransformIdentity, +dx, 0.0);
                }
            }];
        }
    } completion:completion];
    
    0 讨论(0)
  • 2020-12-02 05:31

    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.

    0 讨论(0)
提交回复
热议问题