使用UIImageViewanimation创buildstream畅的animation
我目前正在这样的4个图像之间进行animation处理:
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];
它工作正常,除了animation之间的图像波涛汹涌。 我需要的持续时间正好是0.75秒,所以加速不是一个选项。
让animation在图像之间更平滑的最佳方式是什么?
谢谢!
如果你使用的是基于UIImageView的animation,并且animation必须是0.75秒,那么我所知道的唯一方法就是创build更多的帧。 尝试30帧/秒,或约22帧。 这应该是非常顺利的议案。
如果你想在帧之间进行交叉融合,那么你将无法使用UIView框架animation。 你将不得不使用UIView块animation(使用animateWithDuration:animations:
或其堂兄)。
你可以在你的帧之间创build一个序列,它的总持续时间是0.75秒。 让每个转换触发完成块中的下一个转换。
像这样的东西:
你需要2个图像视图,堆叠在一起。 你会同时淡出一个和另一个。 您需要将两个不透明标志设置为NO。
让我们叫他们tom3BeforeImage1和tom3BeforeImage2
添加一个int实例variablesimageCount,并创build图像数组,tom3Images和实例variables:
- (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:
我不知道为什么,但是我决定把这个做成一个完整的示例项目。 上面的代码在debugging后可以很好地工作,但是由于它在同一时间衰落了一个图像,所以两个图像视图背后的背景都显示出来了。
我重写了它的逻辑,只是淡出顶部的图像。 它将第一帧放在顶部图像视图中,第二帧放在底部图像视图中,然后淡出顶部图像视图。
这个项目在github上,名为Animate-Img 。 (链接)
然后它将第三帧安装在顶部图像视图中并淡入IN,
然后在底部图像视图中安装第四个声望并淡出顶部以暴露底部等等。
我最终创build了一个通用的方法
- (void) animateImagesWithDuration: (CGFloat) totalDuration reverse: (BOOL) reverse crossfade: (BOOL) doCrossfade withCompletionBlock: (void (^)(void)) completionBlock;
它会将一组图像animation化,形成一对图像视图,一旦完成,可以select反转animation。 一旦animation完成,就会调用一个完成块。
animationbutton实际上调用重复整个animation序列的方法。 目前它只能运行一次,但如果需要,改变一个常量将使程序重复整个序列。
我确实有要求与图像arrays的animation。 最初,当我使用imageview的animationImages
属性,我得到了所需的animation,但图像之间的过渡不平滑,然后我使用CAKeyframeAnimation
实现平滑过渡,捕捉是使用timingFunction
与正确的calculationMode
。 我不确定这是否是这个问题的确切答案,但这是使animation更平滑的一种方法,下面是代码
有关计算模式的更多信息,请参阅Apple文档
- (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"]; }
更新 – 斯威夫特3
func animate() { var imageArray = [CGImage]() let imageCount: Int = 3 for i in 0...imageCount { imageArray.append((UIImage(named: String(format:"image\(i)"))?.cgImage!)!) } let animation = CAKeyframeAnimation(keyPath: "contents") animation.calculationMode = kCAAnimationLinear // Make sure this is kCAAnimationLinear or kCAAnimationCubic other mode doesnt consider the timing function animation.duration = CFTimeInterval(floatLiteral: 8.0) animation.values = imageArray animation.repeatCount = 1 // Change it for repetition animation.isRemovedOnCompletion = false animation.fillMode = kCAFillModeForwards // To keep the last frame when animation ends animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) animImageView.layer.add(animation, forKey: "animation") }