ios 如何创建iphone的摆动图标效果?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/929364/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to create iphone's wobbling icon effect?
提问by jeanniey
I want to wobble an image back and forth in my application similar to how the iPhone icons wobble when you press down on it. What's the best way to do that?
我想在我的应用程序中来回摆动图像,类似于按下它时 iPhone 图标的摆动方式。这样做的最佳方法是什么?
This is my first foray into animations that's not using an animated GIF. I think the idea is to slightly rotate the image back and forth to create the wobbling effect. I've looked at using CABasicAnimation and CAKeyframeAnimation. CABasicAnimation creates a jitter every time it repeats because it jumps to the from position and doesn't interpolate back. CAKeyframeAnimation seems like the solution except that I can't get it to work. I must be missing something. Here's my code using the CAKeyframeAnimation (which doesn't work):
这是我第一次尝试不使用动画 GIF 的动画。我认为这个想法是来回稍微旋转图像以创建摆动效果。我看过使用 CABasicAnimation 和 CAKeyframeAnimation。CABasicAnimation 每次重复时都会产生抖动,因为它会跳到起始位置并且不会向后插入。CAKeyframeAnimation 似乎是解决方案,只是我无法让它工作。我肯定错过了什么。这是我使用 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];
Or there could be a totally simpler solution that I'm just missing. Appreciate any pointers. Thanks!
或者可能有一个我只是缺少的完全简单的解决方案。感谢任何指针。谢谢!
回答by Ramin
Simple way to do it:
简单的方法:
#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;
}
}
Probably have to play with timing and angles but this should get you started.
可能需要考虑时间和角度,但这应该会让你开始。
EDIT: I edited the response to add code to put the item back in its original state when done. Also, note that you can use the beginAnimations
context value to pass along anything to the start/stop methods. In this case it's the wobbling object itself so you don't have to rely on specific ivars and the method can be used for any generic UIView-based object (i.e. text labels, images, etc.)
编辑:我编辑了响应以添加代码以在完成后将项目恢复到原始状态。另请注意,您可以使用beginAnimations
上下文值将任何内容传递给 start/stop 方法。在这种情况下,它是摆动对象本身,因此您不必依赖特定的 ivars,并且该方法可用于任何基于 UIView 的通用对象(即文本标签、图像等)
回答by Pieter
Ramin's answer was very good, but since OS4 the same effect can be achieved using animateWithDuration in one simple function too.
Ramin 的回答非常好,但由于 OS4 也可以在一个简单的函数中使用 animateWithDuration 来实现相同的效果。
(adapted his example for future googlers)
(为未来的谷歌员工改编了他的例子)
#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
];
}
回答by docchang
You should use CAKeyframeAnimation
to make a smoother animation.
您应该使用CAKeyframeAnimation
来制作更流畅的动画。
+ (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];
}
回答by Kristopher Johnson
I have written a sample app that attempts to replicate the home screen wobble and icon movement: iPhone Sample Code: Tiles
我编写了一个示例应用程序,试图复制主屏幕摆动和图标移动:iPhone 示例代码:瓷砖
回答by Allen Conquest
For anyone who has come across this posting more recently and would like to do the same in Swift, here is my translation:
对于最近看到这篇文章并想在 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)
}
回答by Thanks
The easiest way I know is to use Core Animation. Basically, you create an Core Animation Block, then do an rotation transform and setup and repeat count. Core Animation then takes care of everything that's needed to do this wobbling effect.
我知道的最简单的方法是使用 Core Animation。基本上,您创建一个核心动画块,然后进行旋转变换和设置并重复计数。然后,核心动画会处理完成这种摇摆效果所需的一切。
To start an Core Animation block, just do:
要启动核心动画块,只需执行以下操作:
[UIView beginAnimations:@"any string as animationID" context:self];
[UIView setAnimationRepeatCount:10];
// rotate
[UIView commitAnimations];
not tested. But it can be that you will also have to do:
未测试。但也有可能您还必须执行以下操作:
[UIView setAnimationBeginsFromCurrentState:YES];
A.F.A.I.K. setAnimationRepeatCount will have the effect that the animation gets done, undone, done, undone, done, undone, done... as many times as you specify. So you may want to first rotate to left with no repeat count, and then from this point start wobbling with repeat count. When done, you may want to rotate back to the identity transform (= no rotation and scaling applied).
AFAIK setAnimationRepeatCount 将具有动画完成、撤消、完成、撤消、完成、撤消、完成...的效果,次数与您指定的次数相同。因此,您可能希望先向左旋转,不重复计数,然后从这一点开始以重复计数开始摆动。完成后,您可能希望旋转回恒等变换(= 不应用旋转和缩放)。
You can chain animations by setting the animation delegate with
您可以通过设置动画委托来链接动画
[UIView setAnimationDelegate:self]
and then
进而
[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];
and as soon as the animation stops, that method will be called. See the UIView class documentation for how to implement that method that will be called when the animation stops. Basically, inside that method you would perform the next step (i.e. rotating back, or anything else), with an new animation block but same context and animation ID, and then (if needed) specify another didStopSelector.
一旦动画停止,就会调用该方法。请参阅 UIView 类文档,了解如何实现将在动画停止时调用的方法。基本上,在该方法中,您将执行下一步(即向后旋转或其他任何操作),使用新动画块但上下文和动画 ID 相同,然后(如果需要)指定另一个 didStopSelector。
UPDATE:
更新:
You may want to check out:
您可能想查看:
[UIView setAnimationRepeatAutoreverses:YES];
this will wobble back and forth automatically.
这将自动来回摆动。
回答by Berik
You can create a not-endless wobble effect using the CAKeyframeAnimation
, like so:
您可以使用 来创建无限的摆动效果CAKeyframeAnimation
,如下所示:
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"];
回答by Jagie
from above answers, I got the swift5 version:
从上面的答案中,我得到了 swift5 版本:
func startWobble() {
let angle = 5.0 * Double.pi / 180.0;
self.transform = CGAffineTransform.identity.rotated(by: CGFloat(-angle));
UIView.animate(withDuration: 0.25, delay: 0, options: [.allowUserInteraction,.repeat,.autoreverse], animations: {
self.transform = CGAffineTransform.identity.rotated(by: CGFloat(angle));
}, completion: nil)
}
func stopWobble() {
UIView.animate(withDuration: 0.25, delay: 0, options: [.allowUserInteraction,.beginFromCurrentState,.curveLinear], animations: {
self.transform = CGAffineTransform.identity;
}, completion: nil)
}
回答by EsbenB
Late to the party. I'm typically using spring with damping (iOS7 and newer). In swift it looks like:
聚会迟到了。我通常使用带阻尼的弹簧(iOS7 和更新版本)。在 swift 中它看起来像:
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
}
You can tweak the effect by adjusting the initialSpringVelocity
and SpringWithDamping
您可以通过调整initialSpringVelocity
和调整效果SpringWithDamping
回答by user599849
Based on EsbenB's answer, but updated for Swift 3 and for rotation:
基于 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)