按顺序使用图像数组的animation

我有一系列的图像,我想通过连续播放这些图像来进行animation处理。 我想多次重复整个循环。 我正在为iPad开发一款游戏。 向我build议一个方法,在Objective-C中用Cocoa框架实现这个function。

查看UIImageViewanimationImages属性。 很难说是否适合您的需求,因为您不提供详细信息,但这是一个好的开始。

 NSArray *animationArray = [NSArray arrayWithObjects: [UIImage imageNamed:@"images.jpg"], [UIImage imageNamed:@"images1.jpg"], [UIImage imageNamed:@"images5.jpg"], [UIImage imageNamed:@"index3.jpg"], nil]; UIImageView *animationView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0,320, 460)]; animationView.backgroundColor = [UIColor purpleColor]; animationView.animationImages = animationArray; animationView.animationDuration = 1.5; animationView.animationRepeatCount = 0; [animationView startAnimating]; [self.view addSubview:animationView]; [animationView release]; 

在array.repeat中添加你自己的图片Count 0意味着无限循环。你也可以给自己的数字。

至less有三种方法可以通过UIImageView对一组图像进行animation处理。 我添加3个链接下载3种可能性的示例代码。

第一个是大家都知道的。 其他人不太了解。

– UIImageView.animationImages
示例链接

这个问题是没有委托人告诉我们animation是在哪一刻完成的。 所以,如果我们想在animation之后显示一些东西,我们可能会遇到问题。

同样,也不可能自动保留UIImageViewanimation的最后一张图片。 如果我们把两个问题结合起来,如果我们想把最后一帧保留在屏幕上,我们可以在animation结尾处有一个空白。

 self.imageView.animationImages = self.imagesArray; // the array with the images self.imageView.animationDuration = kAnimationDuration; // static const with your value self.imageView.animationRepeatCount = 1; [self.imageView startAnimating]; 

– CAKeyframeAnimation
示例链接

这种方式通过CAAnimationanimation作品。 它有一个简单的代表使用,我们可以知道什么时候animation完成。

这可能是使图像arraysanimation的最佳方式。

 - (void)animateImages { CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; keyframeAnimation.values = self.imagesArray; keyframeAnimation.repeatCount = 1.0f; keyframeAnimation.duration = kAnimationDuration; // static const with your value keyframeAnimation.delegate = self; // keyframeAnimation.removedOnCompletion = YES; keyframeAnimation.removedOnCompletion = NO; keyframeAnimation.fillMode = kCAFillModeForwards; CALayer *layer = self.animationImageView.layer; [layer addAnimation:keyframeAnimation forKey:@"girlAnimation"]; } 

代表:

 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if (flag) { // your code } } 

– CADisplayLink
示例链接

A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.

这样做是非常有趣的,并打开了很多的可能性来操纵我们在屏幕上显示的东西。

DisplayLink获取器:

 - (CADisplayLink *)displayLink { if (!_displayLink) { _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(linkProgress)]; } return _displayLink; } 

方法:

 - (void)animateImages { self.displayLink.frameInterval = 5; self.frameNumber = 0; [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; } - (void)linkProgress { if (self.frameNumber > 16) { [self.displayLink invalidate]; self.displayLink = nil; self.animationImageView.image = [UIImage imageNamed:@"lastImageName"]; self.imagesArray = nil; return; } self.animationImageView.image = self.imagesArray[self.frameNumber++]; self.frameNumber++; } 

一般问题:

即使我们有这3种可能性,如果您的animation有很多大的图像,请考虑使用video。 内存的使用会减less很多。

您将要面对的一个常见问题是在分配图像的时刻。

如果你使用[UIImage imageNamed:@“imageName”]你会有cahe问题。

从苹果:

This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method locates and loads the image data from disk or asset catelog, and then returns the resulting object. You can not assume that this method is thread safe.

因此, imageNamed:将图像存储在私人caching中。
– 第一个问题是您无法控制caching大小。
– 第二个问题是caching没有及时清理,如果你用imageNamed:分配了大量的图像,你的应用程序可能会崩溃。

解:

直接从Bundle分配图像:

 NSString *imageName = [NSString stringWithFormat:@"imageName.png"]; NSString *path = [[NSBundle mainBundle] pathForResource:imageName // Allocating images with imageWithContentsOfFile makes images to do not cache. UIImage *image = [UIImage imageWithContentsOfFile:path]; 

小问题:

Images.xcassets图像从不分配。 所以,将您的图像Images.xcassets之外直接从Bundle分配。

对我来说最好的解决scheme是使用CADisplayLink。 UIImageView没有完成块,你不能捕捉animation的步骤。 在我的任务中,我必须逐步改变图像序列器的背景。 所以CADisplayLink允许你处理步骤和完成animation。 如果我们谈论内存的使用,我认为最好的解决scheme是从bundle中加载图像,并在完成后删除数组

ImageSequencer.h

 typedef void (^Block)(void); @protocol ImageSequencerDelegate; @interface QSImageSequencer : UIImageView @property (nonatomic, weak) id <ImageSequencerDelegate> delegate; - (void)startAnimatingWithCompletionBlock:(Block)block; @end @protocol ImageSequencerDelegate <NSObject> @optional - (void)animationDidStart; - (void)animationDidStop; - (void)didChangeImage:(UIImage *)image; @end 

ImageSequencer.m

 - (instancetype)init { if (self = [super init]) { _imagesArray = [NSMutableArray array]; self.image = [self.imagesArray firstObject]; } return self; } #pragma mark - Animation - (void)startAnimating { [self startAnimatingWithCompletionBlock:nil]; } - (void)startAnimatingWithCompletionBlock:(Block)block { self.frameNumber = 0; [self setSuccessBlock:block]; self.displayLink.frameInterval = 5; if (self.delegate && [self.delegate respondsToSelector:@selector(animationDidStart)]) { [self.delegate animationDidStart]; } [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; } -(void)stopAnimating { self.image = [self.imagesArray lastObject]; [self.displayLink invalidate]; [self setDisplayLink:nil]; Block block_ = [self successBlock]; if (block_) { block_(); } if (self.delegate && [self.delegate respondsToSelector:@selector(animationDidStop)]) { [self.delegate animationDidStop]; } [self.imagesArray removeAllObjects]; } - (void)animationProgress { if (self.frameNumber >= self.imagesArray.count) { [self stopAnimating]; return; } if (self.delegate && [self.delegate respondsToSelector:@selector(didChangeImage:)]) { [self.delegate didChangeImage:self.imagesArray[self.frameNumber]]; } self.image = self.imagesArray[self.frameNumber]; self.frameNumber++; } #pragma mark - Getters / Setters - (CADisplayLink *)displayLink { if (!_displayLink){ _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(animationProgress)]; } return _displayLink; } - (NSMutableArray<UIImage *> *)imagesArray { if (_imagesArray.count == 0) { // get images from bundle and set to array } return _imagesArray; } @end 

我已经为此添加了一个快速的3.0扩展

 extension UIImageView { func animate(images: [UIImage], index: Int = 0, completionHandler: (() -> Void)?) { UIView.transition(with: self, duration: 0.5, options: .transitionCrossDissolve, animations: { self.image = images[index] }, completion: { value in let idx = index == images.count-1 ? 0 : index+1 if idx == 0 { completionHandler!() } else { self.animate(images: images, index: idx, completionHandler: completionHandler) } }) } }