如何创buildiphone的摇摆图标效果?
我想在我的应用程序中来回晃动图像,类似于iPhone图标在按下时摆动的方式。 什么是最好的方式来做到这一点?
这是我第一次尝试不使用animationGIF的animation。 我认为这个想法是稍微旋转图像来创造摇摆的效果。 我看过使用CABasicAnimation和CAKeyframeAnimation。 CABasicAnimation每次重复都会产生一个抖动,因为它跳转到from位置,并且不会内插回来。 CAKeyframeAnimation似乎是解决scheme,除了我不能得到它的工作。 我一定会错过一些东西。 这是我的代码使用CAKeyframeAnimation(不起作用):
NSString *keypath = @"wobbleImage"; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:keypath]; animation.duration = 1.0f; animation.delegate = self; animation.repeatCount = 5; CGFloat wobbleAngle = 0.0872664626f; NSValue *initial = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 0.0f, 0.0f, 1.0f)]; NSValue *middle = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(wobbleAngle, 0.0f, 0.0f, 1.0f)]; NSValue *final = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(-wobbleAngle, 0.0f, 0.0f, 1.0f)]; animation.values = [NSArray arrayWithObjects:initial, middle, final, nil]; [imageView.layer addAnimation:animation forKey:keypath];
或者可能有一个完全简单的解决scheme,我只是想念。 欣赏任何指针。 谢谢!
简单的方法来做到这一点:
#define RADIANS(degrees) (((degrees) * M_PI) / 180.0) CGAffineTransform leftWobble = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(-5.0)); CGAffineTransform rightWobble = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(5.0)); itemView.transform = leftWobble; // starting point [UIView beginAnimations:@"wobble" context:itemView]; [UIView setAnimationRepeatAutoreverses:YES]; // important [UIView setAnimationRepeatCount:10]; [UIView setAnimationDuration:0.25]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(wobbleEnded:finished:context:)]; itemView.transform = rightWobble; // end here & auto-reverse [UIView commitAnimations]; ... - (void) wobbleEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { if ([finished boolValue]) { UIView* item = (UIView *)context; item.transform = CGAffineTransformIdentity; } }
可能要玩的时间和angular度,但这应该让你开始。
编辑:我编辑的响应添加代码,把项目回到原来的状态时完成。 另外,请注意,您可以使用beginAnimations
上下文值将任何内容传递给start / stop方法。 在这种情况下,它是摇摆的对象本身,所以你不必依赖特定的Ivars,并且该方法可以用于任何通用的基于UIView的对象(即文本标签,图像等)
Ramin的答案非常好,但是从OS4开始,在一个简单的函数中使用animateWithDuration也可以达到同样的效果。
(改编他的未来谷歌的例子)
#define RADIANS(degrees) (((degrees) * M_PI) / 180.0) - (void)startWobble { itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(-5)); [UIView animateWithDuration:0.25 delay:0.0 options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse) animations:^ { itemView.transform = CGAffineTransformRotate(CGAffineTransformIdentity, RADIANS(5)); } completion:NULL ]; } - (void)stopWobble { [UIView animateWithDuration:0.25 delay:0.0 options:(UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveLinear) animations:^ { itemView.transform = CGAffineTransformIdentity; } completion:NULL ]; }
你应该使用CAKeyframeAnimation
来制作更stream畅的animation。
+ (void) animationKeyFramed: (CALayer *) layer delegate: (id) object forKey: (NSString *) key { CAKeyframeAnimation *animation; animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.duration = 0.4; animation.cumulative = YES; animation.repeatCount = 2; animation.values = [NSArray arrayWithObjects: [NSNumber numberWithFloat: 0.0], [NSNumber numberWithFloat: RADIANS(-9.0)], [NSNumber numberWithFloat: 0.0], [NSNumber numberWithFloat: RADIANS(9.0)], [NSNumber numberWithFloat: 0.0], nil]; animation.fillMode = kCAFillModeForwards; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; animation.removedOnCompletion = NO; animation.delegate = object; [layer addAnimation:animation forKey:key]; }
我写了一个示例应用程序,试图复制主屏幕摆动和图标移动: iPhone示例代码:瓷砖
我知道的最简单的方法是使用核心animation。 基本上,你创build一个核心animation块,然后做一个旋转变换和设置和重复计数。 核心animation然后照顾一切需要做这个摇摆的效果。
要启动一个核心animation块,只需要:
[UIView beginAnimations:@"any string as animationID" context:self]; [UIView setAnimationRepeatCount:10]; // rotate [UIView commitAnimations];
未经testing。 但是,也可能是你也必须这样做:
[UIView setAnimationBeginsFromCurrentState:YES];
AFAIK setAnimationRepeatCount将具有animation完成,撤消,完成,撤消,完成,撤消,完成…的次数,如您指定的次数。 所以你可能要先旋转到左边没有重复计数,然后从这一点开始摇摆重复计数。 完成后,您可能需要旋转回身份转换(=不应用旋转和缩放)。
您可以通过设置animation委托来链接animation
[UIView setAnimationDelegate:self]
接着
[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
一旦animation停止,该方法将被调用。 有关如何实现在animation停止时将被调用的方法,请参阅UIView类文档。 基本上,在该方法中,您将执行下一步(即回旋或其他任何操作),并使用新的animation块,但具有相同的上下文和animationID,然后(如果需要)指定另一个didStopSelector。
更新:
你可能想看看:
[UIView setAnimationRepeatAutoreverses:YES];
这会自动地来回摆动。
您可以使用CAKeyframeAnimation
创build一个没有无限的摆动效果,如下所示:
CGFloat degrees = 8.0; CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.duration = 0.6; animation.cumulative = YES; animation.repeatCount = 1; animation.values = @[@0.0, @RADIANS(-degrees) * 0.25, @0.0, @RADIANS(degrees) * 0.5, @0.0, @RADIANS(-degrees), @0.0, @RADIANS(degrees), @0.0, @RADIANS(-degrees) * 0.5, @0.0, @RADIANS(degrees) * 0.25, @0.0]; animation.fillMode = kCAFillModeForwards; animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; animation.removedOnCompletion = YES; [self.layer addAnimation:animation forKey:@"wobble"];
对于最近遇到这个post的人,并希望在Swift中也这样做,这是我的翻译:
func smoothJiggle() { let degrees: CGFloat = 5.0 let animation = CAKeyframeAnimation(keyPath: "transform.rotation.z") animation.duration = 0.6 animation.cumulative = true animation.repeatCount = Float.infinity animation.values = [0.0, degreesToRadians(-degrees) * 0.25, 0.0, degreesToRadians(degrees) * 0.5, 0.0, degreesToRadians(-degrees), 0.0, degreesToRadians(degrees), 0.0, degreesToRadians(-degrees) * 0.5, 0.0, degreesToRadians(degrees) * 0.25, 0.0] animation.fillMode = kCAFillModeForwards; animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) animation.removedOnCompletion = true layer.addAnimation(animation, forKey: "wobble") } func stopJiggling() { jiggling = false self.layer.removeAllAnimations() self.transform = CGAffineTransformIdentity self.layer.anchorPoint = CGPointMake(0.5, 0.5) }
晚会到了晚会 我通常使用阻尼弹簧(iOS7和更新版本)。 在迅速它看起来像:
sender.transform = CGAffineTransformMakeScale(1.2, 1.2) UIView.animateWithDuration(0.30, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.3, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in sender.transform = CGAffineTransformMakeScale(1, 1) }) { (Bool) -> Void in //Do stuff when animation is finished }
您可以通过调整initialSpringVelocity
和SpringWithDamping
来调整效果
基于EsbenB的回答,但更新了Swift 3和轮换:
sender.transform = CGAffineTransform(rotationAngle: 12.0 * .pi / 180.0) UIView.animate(withDuration: 0.60, delay: 0.0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.3, options: .curveEaseInOut, animations: { () -> Void in sender.transform = CGAffineTransform(rotationAngle: 0.0) }, completion: nil)
那么Ramin给出的代码工作的很好。但是,如果你使用tabbar应用程序,并移动到下一个标签项目,然后再回到以前的标签项目,你会看到你的看法已经移动到左侧,每次。所以最好的做法是你使用ViewWillAppear方法。
- (void)viewWillAppear:(BOOL)animated { UIView* item = self.view; item.transform = CGAffineTransformIdentity; }
所以每次加载视图,你都会在正确的位置find你的animation,并且也使用这个方法。
[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
Swift 3
func startWiggling() { deleteButton.isHidden = false guard contentView.layer.animation(forKey: "wiggle") == nil else { return } guard contentView.layer.animation(forKey: "bounce") == nil else { return } let angle = 0.04 let wiggle = CAKeyframeAnimation(keyPath: "transform.rotation.z") wiggle.values = [-angle, angle] wiggle.autoreverses = true wiggle.duration = randomInterval(0.1, variance: 0.025) wiggle.repeatCount = Float.infinity contentView.layer.add(wiggle, forKey: "wiggle") let bounce = CAKeyframeAnimation(keyPath: "transform.translation.y") bounce.values = [4.0, 0.0] bounce.autoreverses = true bounce.duration = randomInterval(0.12, variance: 0.025) bounce.repeatCount = Float.infinity contentView.layer.add(bounce, forKey: "bounce") } func stopWiggling() { deleteButton.isHidden = true contentView.layer.removeAllAnimations() }