在iPhone上摇动视觉效果(不摇动设备)

在login失败的时候,我宁愿避免显示警报,这太短暂了。 显示警报,然后在login屏幕上显示文本似乎是重复的。

所以我希望当用户input错误的用户名和密码(如Maclogin屏幕)时,以graphics的方式摇动我的login视图。

任何人都知道是否有办法把这个closures,或有任何build议,我可以使用另一个效果?

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

迅速:

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

只有一个animation对象被创build,并且全部在CoreAnimation级别上执行。

使用iOS 4 +基于块的UIKitanimation(松散地基于jayccrown的答案):

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

我曾经看过一些摆动animation,并改变了它的视图像素正立和左下:

 - (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; } } 

这里有一个教程,详细介绍如何在Cocoa中做到这一点。 应该是相同的iPhone(或至less非常相似)。

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

简单地改变视图的中心属性的X坐标可能会有所裨益。 如果你之前还没有做过任何核心animation,那么它很简单。

首先,开始一个animation,然后听它完成,然后回到左侧,依此类推。 让时机下降,使其“感觉正确”可能需要一段时间。

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

这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 

希望它能救人:)

在iOS 7.0或更高版本中,UIKit关键帧animation可用。

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

我知道这个问题已经得到解答,但是由于我已经实现了这样的东西,所以我觉得不妨添加它:

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

此外,由于您希望抖动表示用户login失败,因此您可能还会考虑添加此animation,在屏幕抖动时将屏幕变为红色:

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

希望这可以帮助!

使用自动布局,我改编了Chris Miles的答案,但是这样做了NSLayoutConstraints的animation:

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

我用于约束的解决scheme,我在故事板中设置。 不使用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 } } 

在我的情况下,animation只是继续前进,但在几秒钟的时间之后,我popupviewcontroller,这也停止了我的计时器。