使用UIImageView动画创建平滑动画

时间:2014-01-19 03:03:46

标签: ios objective-c

我目前正在制作4张这样的图像:

UIImageView *tom3BeforeImage;
tom3Images = [NSArray arrayWithObjects: [UIImage imageNamed:@"floortom_before1.png"],[UIImage imageNamed:@"floortom_before2.png"],[UIImage imageNamed:@"floortom_before3.png"],[UIImage imageNamed:@"floortom_before4.png"], nil ];
tom3BeforeImage.animationImages = tom3Images;
tom3BeforeImage.animationDuration = 0.75;
[tom3BeforeImage startAnimating];

它工作正常,但动画在图像之间不稳定。我需要持续时间精确到0.75秒,所以加速它不是一个选择。

让动画在图像之间更平滑的最佳方法是什么,有点像在每次图像变化之间进行混合?

谢谢!

2 个答案:

答案 0 :(得分:4)

如果您正在使用基于帧的UIImageView动画,并且动画必须是.75秒,那么我知道的唯一方法是使其更流畅是创建更多帧。尝试30帧/秒,或约22帧。这应该是非常平稳的动作。

如果你想在帧之间进行某种交叉溶解,那么你将无法使用UIView帧动画。你将不得不使用UIView块动画(使用animateWithDuration:animations:或其表兄弟。)

您可以在帧之间创建一系列交叉溶解,其中序列的总持续时间为.75秒。让每个转换触发其完成块中的下一个转换。

这样的事情:

您需要两个图像视图,彼此叠加。你会同时淡出一个,另一个淡入淡出。您需要在两者上将opaque标志设置为NO。

让我们称之为tom3BeforeImage1和tom3BeforeImage2

添加一个int实例变量imageCount并制作你的图像数组,tom3Images和实例变量:

- (void) animateImages;
{
  CGFloat duration = .75 / ([tom3Images count] -1);

  //Start with the current image fully visible in tom3BeforeImage1
  tom3BeforeImage1.image = tom3Images[imageCount];
  tom3BeforeImage1.alpha = 1.0;

  //Get the next image ready, at alpha 0, in tom3BeforeImage2
  tom3BeforeImage2.image = tom3Images[imageCount+1];
  tom3BeforeImage2.alpha = 0;
  imageCount++

  [UIView animateWithDuration: duration  
    delay: 0 
    options: UIViewAnimationOptionCurveLinear
    animations:
    ^{
      //Fade out the current image
       tom3BeforeImage1.alpha = 0.0;

       //Fade in the new image
       tom3BeforeImage2.alpha = 1.0;
    }
    completion:
    ^{
    //When the current animation step completes, trigger the method again.
    if (imageCount < [tom3Images count] -1)
       [self animateImages];
    }
  ];
}

请注意,在没有足够咖啡的情况下,我在论坛编辑器中删除了上面的代码。它可能包含语法错误,甚至可能存在逻辑问题。这只是为了让你思考如何做到这一点。

编辑#2:

我不知道为什么,但我决定将其充实为一个成熟的示例项目。上面的代码在调试后可以很好地工作,但是由于它同时淡化了一个图像,它正在淡化另一个图像,两个图像视图背后的背景显示出来。

我将其重新设计为具有仅消除顶部图像的逻辑。它将第一帧放在顶部图像视图中,将第二帧放在底部图像视图中,然后淡出顶部图像视图。

该项目在github上发布,名为Animate-Img。 (链接)

然后它在顶部图像视图中安装第三帧并将其淡入IN,

然后它在底部图像视图中安装第4个成名并淡出顶部以暴露底部等等。

我最终创建了一个通用方法

- (void) animateImagesWithDuration: (CGFloat) totalDuration
                           reverse: (BOOL) reverse
                         crossfade: (BOOL) doCrossfade
               withCompletionBlock: (void (^)(void)) completionBlock;

它会将一组图像动画化为一对图像视图,可选择在动画完成后将其反转。它需要一个动画完成后调用的完成块。

动画按钮实际上调用重复整个动画序列的方法。它目前设置为仅运行一次,但是如果需要,更改常量将使程序重复整个序列。

答案 1 :(得分:3)

我确实要求拥有包含图像数组的动画。最初,当我使用imageview的animationImages属性时,我得到了所需的动画,但是图像之间的过渡并不平滑,然后我使用CAKeyframeAnimation来实现平滑过渡,捕获是使用{{1与正确的timingFunction一起。我不确定这是问题的答案,但这是使动画更流畅的一种方法,  下面是那个

的代码

有关计算模式的详细信息,请参阅Apple Documentation

calculationMode

UPDATE- Swift 3

- (void) animate
{
    NSMutableArray * imageArray = [[NSMutableArray alloc] init];

    int imageCount = 8;

    for (int i=0; i<=imageCount; i++) {
        [imageArray addObject:(id)[UIImage imageNamed:[NSString stringWithFormat:@“image%d”,i]].CGImage];
    }

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
    animation.calculationMode = kCAAnimationLinear;// Make sure this is kCAAnimationLinear or kCAAnimationCubic other mode doesnt consider the timing function
    animation.duration = 8.0;
    animation.values = imageArray;
    animation.repeatCount = 1; // Change it for repetition
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards; // To keep the last frame when animation ends
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [imageView.layer addAnimation:animation forKey:@"animation"];
}