2013-02-18 144 views
8

我有以下简单的UIImageView动画:停止动画的UIImageView逐渐平稳

-(void) setupTheAnimation { 
    self.imgView.animationImages = imagesArr; 
    [self.imgView setAnimationRepeatCount:-1]; 
    self.imgView.animationDuration =0.9; 
    [self.imgView startAnimating]; 
    [self performSelector:@selector(stopTheAnimation) withObject:nil afterDelay:4.0]; 
} 

-(void) stopTheAnimation { 
    [self.imgView stopAnimating]; 
} 

但是当动画停止,我不知道什么是它停止在最后一帧我面对的一个问题!所以动画的结局根本不流畅。

,所以我需要:

1)知道什么是最后一帧处的动画结束了,所以我把它作为动画的最后一个图像,这导致了平稳停车。

2)逐渐停止该动画,即在停止之前改变其持续时间以使其先减速并停止。

This is a link to the sample project

+1

好问题:) – 2013-02-18 14:03:24

+0

我想说这需要作为一个自定义的动画属性实现在UIImageView的子类上,在这里你重复地将图层的内容设置为图像阵列中的图像提供定时功能。不会太难,但我不认为有可能通过'UIImageView'的'animationImages'来完成缓解效果。 – 2013-02-24 08:54:50

回答

2

我知道你的最初实现使用animationImages,但我不知道的方式来使用animationImages直接具有连续可变的持续时间。但是,这是一个非常简单的功能来实现自己。如果你这样做,那么你可以在你的数组中的图像之间编码一个动态持续时间值。

在下面的代码,我取代animationImages使用自定义步进功能,并动态调整后停止已被请求的持续时间。请注意,这与您的原始代码有点不同,它指定了一段艰难的结束时间。此代码指定齿轮旋转应在何时开始开始减速。

如果你真的有一个硬动画时期,你可以调整到stopTheAnimation来考虑你选择的减速因素(我只是在减速期间每步增加10%的持续时间,直到步骤比给定的阈值):

// my animation stops when the step duration reaches this value: 
#define STOP_THRESHOLD_SECONDS 0.1f 
#define NUM_IMAGES 35 

@implementation ViewController 
{ 
    NSMutableArray *imagesArr; 
    int currentImage; 
    BOOL stopRequested; 
    NSTimeInterval duration; 
} 

-(void) setupTheAnimation { 

    stopRequested = NO; 
    currentImage = 0; 
    duration = 0.9f/NUM_IMAGES; 
    [self stepThroughImages]; 

    [self performSelector:@selector(stopTheAnimation) withObject:nil afterDelay:4.0]; 
} 

- (void) stepThroughImages { 

    self.imgView.image = [imagesArr objectAtIndex: currentImage]; 

    if (currentImage == NUM_IMAGES - 1) { 
     currentImage = 0; 
    } else { 
     currentImage++; 
    } 

    if (stopRequested && duration < STOP_THRESHOLD_SECONDS) { 
     // we're slowing down gradually 
     duration *= 1.1f; 
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)); 
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
      [self stepThroughImages]; 
     }); 
    } else if (!stopRequested) { 
     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)); 
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 
      [self stepThroughImages]; 
     }); 
    } 
} 

-(void) stopTheAnimation { 
    stopRequested = YES; 
} 
+0

真棒...非常感谢你。 – JAHelia 2013-02-25 06:36:51

+0

不客气。我只注意到你的项目中实际上有36张图像(0到35)。所以,也许你应该把我的代码中的'NUM_IMAGES'改为'36',因为我从'0'迭代到'NUM_IMAGES - 1'。我认为在你的'viewDidLoad'方法中初始化'imagesArr'的代码有同样的问题。它实际上并没有加载'GearAnimation35 @ 2x.png'。 – Nate 2013-02-25 07:38:09

0

我只用块知道这一点,但这里是你如何做到这一点:

[UIImageView animateWithDuration:0.9f delay:0.0f options:UIViewAnimationOptionCurveEaseOut animations:^{ 

       // animate what you want 
       self.imgView.transform = CGAffineTransformMakeScale(1.0f, 1.0f); 

      } completion:^(BOOL finished){ 

       // animation is completed 
       self.imgView.image = image; 

      }]; 

选项“UIViewAnimationOptionCurveEaseOut”应该逐渐停止动画。你可以与其他选项一起玩,看看效果。

+0

这不适用于我在问题中发布的animationImages方法。 – JAHelia 2013-02-18 19:07:55

0

你的方法有一个问题:每秒帧数不是恒定的(你减慢时间)。

您确定需要动画吗?

如果您的动画可以通过几何(仿射)转换来实现,那么它会更好。

如果你的动画可以用组合来实现:

  • 翻译
  • 旋转
  • 缩放

那么这是一个仿射变换。

+1

如果他们从头开始完成这项任务,我会100%同意。 3个齿轮中的每一个都可以是用仿射变换旋转的单独图像。但是,由于他们已经得到了36张图片,我可以说这可能是一个很好的工作(可能超出了*编程*和*图形设计的范围)。必须提取四个或五个单独的图像:背景,2/3档位和边框以放置在顶部。此外,齿轮移动的棘轮特性我认为也可以使基于帧的动画的轻微变化成为可接受的。 – Nate 2013-02-24 21:34:29

+0

谢谢Nate。我没有意识到这36个齿轮图像,因为这在原始问题中没有提到。但是你的方式是可以接受的,但是最终的渲染质量仍然很差,因为时间在给定的速度下被分离,并且你需要放慢速度。无论如何。 – 2013-02-25 07:32:52

+0

是的,你必须真正下载完整的项目才能看到,所以从单纯的问题来看肯定不是很明显:) – Nate 2013-02-25 07:34:42