Objective c 按顺序使用图像阵列的动画

Objective c 按顺序使用图像阵列的动画,objective-c,cocoa-touch,ios,animation,Objective C,Cocoa Touch,Ios,Animation,我有一个图像数组,我想通过依次播放这些图像来设置动画。我想把整个循环重复几次。我正在为iPad开发一款游戏。向我建议一种方法,在Objective-C中使用Cocoa框架实现此功能。请参阅的animationImages属性。很难说它是否符合您的需求,因为您没有提供详细信息,但这是一个良好的开端 NSArray *animationArray = [NSArray arrayWithObjects: [UIImage imageNamed:@"

我有一个图像数组,我想通过依次播放这些图像来设置动画。我想把整个循环重复几次。我正在为iPad开发一款游戏。向我建议一种方法,在Objective-C中使用Cocoa框架实现此功能。

请参阅的
animationImages
属性。很难说它是否符合您的需求,因为您没有提供详细信息,但这是一个良好的开端

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];

在数组中添加您自己的图像。重复计数0表示无限循环。您也可以给出您自己的数字。

通过
UIImageView
至少有3种方法可以设置图像数组的动画。我添加了3个链接来下载3种可能性的示例代码

第一个是大家都知道的。其他的则鲜为人知

-UIImageView.animationImages

这一个的问题是,没有委托告诉我们动画在哪一刻完成。因此,如果我们想在动画之后显示某些内容,我们可能会遇到问题

同样,无法在
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];
-cakeyKeyMeanimation

这种动画方式通过
CAAnimation
工作。它有一个易于使用的委托,我们可以知道动画何时完成

这可能是设置图像阵列动画的最佳方法

- (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

CADisplayLink对象是一个计时器对象,允许应用程序将其图形与显示器的刷新率同步。

这样做真的很有趣,并且打开了很多可能性来操纵我们在屏幕上显示的内容

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种可能性,如果你的动画有很多大的图像,考虑使用视频代替。内存的使用将大大减少

执行此操作时,您将面临的一个普遍问题是在分配图像时

如果使用[UIImage imageName:@“imageName”],您将遇到cahe问题

来自苹果:

此方法在系统缓存中查找具有指定名称的图像对象,并返回该对象(如果存在)。如果匹配的图像对象不在缓存中,此方法将从磁盘或资产目录中查找并加载图像数据,然后返回结果对象。您不能假定此方法是线程安全的。

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

解决方案:

直接从
包分配图像

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.xcsets
中的图像从未分配。因此,请将您的图像移动到
images.xcsets
外部,以便直接从捆绑包进行分配。

我的最佳解决方案是使用CADisplayLink。UIImageView没有完成块,您无法捕捉动画的步骤。在我的任务中,我必须用图像序列器一步一步地改变背景视图。因此,CADisplayLink允许您处理步骤和完成动画。若我们讨论内存的使用,我认为最好的解决方案是从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
typedef void(^Block)(void);
@协议图像序列;
@接口QSImageSequencer:UIImageView
@属性(非原子,弱)id委托;
-(void)使用CompletionBlock(块)块启动初始化;
@结束
@协议ImageSequencerDelegate
@可选的
-(void)animationDidStart;
-(void)animationDidStop;
-(void)didChangeImage:(UIImage*)图像;
@结束
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
-(instancetype)初始化{
if(self=[super init]){
_imagesArray=[NSMutableArray];
self.image=[self.imagesArray firstObject];
}
回归自我;
}
#pragma标记-动画
-(无效)启动{
[带完成块的自启动映像:无];
}
-(无效)使用完成块启动初始化:(块)块{
self.frameNumber=0;
[自设置成功块:块];
self.displayLink.frameInterval=5;
if(self.delegate&&[self.delegate respondsToSelector:@selector(animationDidStart)]){
[self.delegate animationDidStart];
}
[self.displayLink addToRunLoop:[NSRunLoop main runloop]
forMode:nsrunlopCommonModes];
}
-(无效)停止设置动画{
self.image=[self.imagesArray lastObject];
[self.displayLink失效];
[自我设置显示链接:无];
Block_uu=[self successBlock];
如果(块){
块_u3;();
}
if(self.delegate&&[self.delegate respondsToSelector:@selector(animationDidStop)]){
[self.delegate animationDidStop];
}
[self.imagesArray removeAllObjects];
}
-(无效)动画进度{
if(self.frameNumber>=self.imagesArray.count){
[自动停止动画];
返回;
}
if(self.delegate&&[self.delegate respondsToSelector:@selector(didChangeImage:)])){
[self.delegate didChangeImage:self.imagesArray[self.frameNumber]];
}
self.image=self.imagesArray[self.frameNumber];
self.frameNumber++;
}
#pragma标记-getter/setter
-(CADisplayLink*)显示链接{
如果(!\u显示链接){
_displayLink=[CADisplayLink displayLinkWithTarget:自选择器:@selector(animationProgress)];
}
返回显示链接;
}
-(NSMutableArray*)图像阵列{
中频成像仪
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)
            }

        })
    }

}
-(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!");
                     }];
}