热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何创造iphone摇摆的图标效果?-howtocreateiphone'swobblingiconeffect?

IwanttowobbleanimagebackandforthinmyapplicationsimilartohowtheiPhoneiconswobblewh

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!

或者有一种完全更简单的解决方案我只是没有。欣赏任何指针。谢谢!

11 个解决方案

#1


91  

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.)

编辑:我编辑响应以添加代码,以便在完成后将项目恢复到原始状态。另外,请注意,您可以使用beginanimation上下文值将任何东西传递给start/stop方法。在本例中,它是抖动对象本身,所以您不必依赖特定的ivars,该方法可以用于任何基于uiview的通用对象(例如文本标签、图像等)。

#2


89  

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

#3


13  

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

#4


9  

I have written a sample app that attempts to replicate the home screen wobble and icon movement: iPhone Sample Code: Tiles

我编写了一个示例应用程序,试图复制主屏幕抖动和图标移动:iPhone样本代码:Tiles。

#5


2  

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。基本上,你创建一个核心动画块,然后做一个旋转变换和设置和重复计数。然后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).

a.f.a.i.k。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.

这将自动来回摆动。

#6


2  

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

#7


2  

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

#8


1  

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

你可以通过调整初始速度和具有阻尼的弹簧来调整效果

#9


1  

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)

#10


0  

Well the code given by Ramin works well.But if you use tabbar application and move to next tab item then again come back to previous tab item,you will see that your view has been moved to left,every time.So the best practice is that you use ViewWillAppear method as.

Ramin给出的代码运行得很好。但是如果您使用tabbar应用程序并移动到下一个选项卡项,然后再次返回到上一个选项卡项,您将看到每次视图都被移动到左边。所以最佳实践是使用ViewWillAppear方法as。

- (void)viewWillAppear:(BOOL)animated
{
    UIView* item = self.view;
    item.transform = CGAffineTransformIdentity;
}

so the every time view is loaded you will find you animation at the right place.And also use this method as well.

因此,每次加载视图时,你都会在正确的地方找到动画。也可以用这种方法。

[UIView setAnimationDidStopSelector:@selector(myMethod:finished:context:)];

#11


0  

Swift 3

斯威夫特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()
}

推荐阅读
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 在重复造轮子的情况下用ProxyServlet反向代理来减少工作量
    像不少公司内部不同团队都会自己研发自己工具产品,当各个产品逐渐成熟,到达了一定的发展瓶颈,同时每个产品都有着自己的入口,用户 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
author-avatar
奎奎201277
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有