ios 按顺序使用图像数组的动画
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6040528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Animation using array of images in sequence
提问by Yadnesh
I have an array of images which I want to animate by playing these images one after the other in a sequence. I want to repeat the whole loop several times. I am developing a game for iPad. Suggest to me a method to achieve this functionality in Objective-C with the Cocoa framework.
我有一组图像,我想通过按顺序一个接一个地播放这些图像来制作动画。我想多次重复整个循环。我正在为 iPad 开发游戏。向我建议一种使用 Cocoa 框架在 Objective-C 中实现此功能的方法。
采纳答案by zoul
See the animationImages
property of UIImageView
. It's hard to say if it fits your needs as you don't give us details, but it's a good start.
见 的animationImages
属性UIImageView
。很难说它是否适合您的需求,因为您没有向我们提供详细信息,但这是一个好的开始。
回答by Gypsa
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];
add your own images in the array.repeat Count 0 means infinite loop.You can give your own number also.
在数组中添加您自己的图像。重复计数 0 表示无限循环。您也可以提供自己的编号。
回答by Gabriel.Massana
There are at least 3 ways to animate an array of images through a UIImageView
. I'm adding 3 links to download sample code for the 3 possibilities.
至少有 3 种方法可以通过UIImageView
. 我正在添加 3 个链接来下载 3 种可能性的示例代码。
The first one is the one that everyone knows. The other ones are less known.
第一个是大家都知道的。其他的则鲜为人知。
- UIImageView.animationImages
Example Link
- UIImageView.animationImages
示例链接
The problem of this one is that do not have Delegate to tell us in which moment the animation is finished. So, we can have problems if we want to display something after the animation.
这个的问题是没有 Delegate 告诉我们动画在哪一刻完成。所以,如果我们想在动画之后显示一些东西,我们可能会遇到问题。
In the same way, there is no possibility to kept the last image from the animation in the UIImageView
automatically. If we combine both problems we can have a gap at the end of the animation if we want to kept the last frame on screen.
以同样的方式,不可能在UIImageView
自动中保留动画中的最后一张图像。如果我们将这两个问题结合起来,如果我们想将最后一帧保留在屏幕上,我们可能会在动画结束时出现间隙。
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
Example Link
- CAKeyframeAnimation
示例链接
This way to animate works through CAAnimation
. It have an easy delegate to use and we can know when the animation finish.
这种动画方式通过CAAnimation
. 它有一个易于使用的委托,我们可以知道动画何时完成。
This is probably the best way to animate an array of images.
这可能是为一系列图像设置动画的最佳方式。
- (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"];
}
Delegate:
代表:
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
if (flag)
{
// your code
}
}
- CADisplayLink
Example Link
- CADisplayLink
示例链接
A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
This way to do it is really interesting and opens a lot of possibilities to manipulate what are we showing in screen.
这种方式真的很有趣,并且为操纵我们在屏幕上显示的内容开辟了很多可能性。
DisplayLink getter:
DisplayLink 获取器:
- (CADisplayLink *)displayLink
{
if (!_displayLink)
{
_displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(linkProgress)];
}
return _displayLink;
}
Methods:
方法:
- (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++;
}
GENERAL PROBLEM:
一般问题:
Even though we have this 3 possibilities, if your animation is with a lot of big images, consider using a video instead. The usage of memory will decrease a lot.
尽管我们有这 3 种可能性,但如果您的动画包含大量大图像,请考虑改用视频。内存的使用会减少很多。
A General problem you will face doing this is in the moment of the allocation of the images.
您在执行此操作时将面临的一个普遍问题是在分配图像时。
If you use [UIImage imageNamed:@"imageName"] you will have cahe problems.
如果你使用 [UIImage imageNamed:@"imageName"] 你会遇到问题。
From Apple:
来自苹果:
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.
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.
So, imageNamed:
stores the image in a private Cache.
- The first problem is that you can not take control of the cache size.
- The second problem is that the cache did not get cleaned in time and if you are allocating a lot of images with imageNamed:
, your app, probably, will crash.
因此,imageNamed:
将图像存储在私有缓存中。
- 第一个问题是您无法控制缓存大小。
- 第二个问题是缓存没有及时清理,如果您使用 分配大量图像imageNamed:
,您的应用程序可能会崩溃。
SOLUTION:
解决方案:
Allocate images directly from Bundle
:
直接从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];
Small problem:
小问题:
Images in Images.xcassets
get never allocated. So, move your images outside Images.xcassets
to allocate directly from Bundle.
Images.xcassets
get 中的图像永远不会分配。因此,将您的图像移到外面Images.xcassets
以直接从 Bundle 分配。
回答by ZaEeM ZaFaR
I have added a swift 3.0 extension for this
我为此添加了一个 swift 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)
}
})
}
}
回答by Dmitry Skidan
Best solution for me use CADisplayLink. UIImageView doesn't have completion block and you can't catch steps of animation. In my task i must changing background of view with image sequencer step by step. So CADisplayLink allows you handling steps and finishing animation. If we talk about usage of memory, i think best solution load images from bundle and delete array after finishing
对我来说最好的解决方案是使用 CADisplayLink。UIImageView 没有完成块,您无法捕捉动画步骤。在我的任务中,我必须逐步使用图像序列器更改视图背景。因此 CADisplayLink 允许您处理步骤和完成动画。如果我们谈论内存的使用,我认为最好的解决方案是在完成后从包中加载图像并删除数组
ImageSequencer.h
图像序列器.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
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
回答by Sooraj s Nair
This is a simple and working code for animation./
这是一个简单且有效的动画代码。/
-(void)move
{
[UIView animateWithDuration:5
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^{
[_imgbox setFrame:CGRectMake(100, 100, _imgbox.frame.size.width, _imgbox.frame.size.height)];
}
completion:^(BOOL finished){
NSLog(@"Done!");
}];
}