Анимация с использованием массива изображений в последовательности - PullRequest
18 голосов
/ 18 мая 2011

У меня есть массив изображений, которые я хочу анимировать, воспроизводя эти изображения одно за другим в последовательности. Я хочу повторить весь цикл несколько раз. Я занимаюсь разработкой игры для iPad. Предложите мне метод для достижения этой функциональности в Objective-C с фреймворком Cocoa.

Ответы [ 6 ]

50 голосов
/ 18 мая 2011
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 означает бесконечный цикл. Вы также можете указать свой номер.

18 голосов
/ 16 января 2015

Существует как минимум 3 способа анимировать массив изображений с помощью UIImageView.Я добавляю 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];

- CAKeyframeAnimation
Пример ссылки

Этот способ анимации работает через 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
Пример ссылки

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 возможности, если ваша анимация содержит много больших изображений, рассмотрите возможность использования видео.Использование памяти значительно уменьшится.

Общая проблема, с которой вы столкнетесь при этом, заключается в моменте выделения изображений.

Если вы используете [UIImage imageNamed: @ "imageName"], у вас возникнут проблемы с *. 1061 *

От 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.

Итак,imageNamed: сохраняет изображение в частном кэше.
- Первая проблема заключается в том, что вы не можете контролировать размер кэша.
- Вторая проблема заключается в том, что кэш не очищался вовремя, и если вывыделяя много изображений с помощью 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.

11 голосов
/ 18 мая 2011

См. animationImages свойство UIImageView. Трудно сказать, соответствует ли он вашим потребностям, поскольку вы не предоставляете нам подробности, но это хорошее начало.

2 голосов
/ 24 января 2017

Я добавил расширение 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)
            }

        })
    }

}
1 голос
/ 07 ноября 2016

Лучшее решение для меня использовать CADisplayLink. UIImageView не имеет блока завершения, и вы не можете поймать шаги анимации. В моей задаче я должен шаг за шагом менять фон изображения с помощью секвенсора изображений. Таким образом, CADisplayLink позволяет вам обрабатывать шаги и заканчивать анимацию. Если говорить об использовании памяти, я думаю, что лучшее решение - загрузить изображения из пакета и удалить массив после окончания

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
0 голосов
/ 24 июня 2018

Это простой и рабочий код для анимации ./

-(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!");
                     }];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...