代码之家  ›  专栏  ›  技术社区  ›  Steven Fisher

iPhone上的抖动视觉效果(不抖动设备)

  •  44
  • Steven Fisher  · 技术社区  · 15 年前

    登录失败时,我希望避免显示警报,因为它太过短暂。显示警报,然后在登录屏幕上的某个位置显示文本似乎是重复。

    有人知道有没有办法做到这一点,或者对我可以使用的另一种效果有什么建议吗?

    11 回复  |  直到 15 年前
        1
  •  97
  •   nielsbot    8 年前

    我认为这是一个更有效的解决方案:

    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 )
    

    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 ] ;
    

    只创建一个动画对象,并且所有对象都在CoreAnimation级别执行。

        2
  •  59
  •   Chris Miles    13 年前

    - (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];
            }
        }];
    }
    
        3
  •  40
  •   jayccrown    15 年前

    我看到了一些抖动动画,并将其更改为垂直和左下晃动视图t像素:

    - (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
  •  8
  •   Justin Gallagher    15 年前

    下面是一个教程,详细介绍了如何在Cocoa中执行此操作。iPhone也应该如此(或者至少相当类似)。

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

        5
  •  6
  •   slf    15 年前

    只需更改视图的“中心”属性的X坐标即可。如果你以前没有做过任何核心动画的话,那就很简单了。

    首先,向右开始一个动画,然后听它完成,然后移回左侧,依此类推。把时间安排下来,让它“感觉正确”可能需要一段时间。

    - (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];
      }
    }
    
        6
  •  4
  •   JakubKnejzlik    12 年前

    这个UIView类别代码片段对我很有用。它使用了3个应用于视图层的CABasingAnimations。

    #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
    

        7
  •  2
  •   ishkawa    10 年前

    在iOS 7.0或更高版本中,可以使用UIKit关键帧动画。

    [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];
    
        8
  •  1
  •   Jonas Schnelli    14 年前
        9
  •  1
  •   pasawaya Katriel    12 年前

    我知道这个问题已经得到了回答,但由于我之前已经实现了类似的功能,我觉得添加它不会有什么坏处:

    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"];
    

    //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"];
    

    希望这有帮助!

        10
  •  0
  •   jay492355    11 年前

    使用自动布局,我调整了Chris Miles的答案,但设置了如下布局约束:

    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];
        }
    }];
    
        11
  •  0
  •   Alserda    8 年前

    @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
        }
    }
    

    在我的例子中,动画一直在继续,但我在几秒钟后弹出我的viewcontroller,这也停止了我的计时器。