Как мне одновременно анимировать изображение UIImageView и сам UIImageView?

Название может быть не таким ясным, но я хочу, чтобы UIImageView отображал серию изображений (вроде как гифку), и я делаю это, устанавливая animationImages на массив изображений и затем вызывая [imageView startAnimating];. Это прекрасно работает. У меня также есть код, который перемещает UIImageView с помощью CABasicAnimation, и этот код анимации также отлично работает. Однако, когда я пытаюсь как анимировать изображения UIImageView, так и перемещать UIImageView, изображения UIImageView перестают анимироваться. Есть ли обходной путь?

Вот мой код для анимации содержимого UIImageView:

    self.playerSprite = [[UIImageView alloc] initWithImage:[self.player.animationImages objectAtIndex:0]];
    [self.playerSprite setFrame:CGRectMake(self.center.x, self.center.y, self.tileSet.constants.TILE_WIDTH, self.tileSet.constants.TILE_HEIGHT)];
    self.playerSprite.animationImages = self.player.animationImages;
    self.playerSprite.animationDuration = self.tileSet.constants.animationDuration;
    self.playerSprite.animationRepeatCount = 0; //Makes it repeat indefinitely

А вот мой код для анимации UIImageView с помощью CABasicAnimation:

float playerSpriteX = self.playerSprite.center.x;
float playerSpriteY = self.playerSprite.center.y;

CABasicAnimation *moveAnimation = [CABasicAnimation animation];
moveAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(playerSpriteX + TILE_WIDTH, playerSpriteY)];
[moveAnimation setDelegate:self];
[moveAnimation setFillMode:kCAFillModeForwards];
[moveAnimation setRemovedOnCompletion:NO];
[moveAnimation setDuration:MOVE_ANIMATION_DURATION];       
[self.playerSprite.layer addAnimation:moveAnimation forKey:@"position"];

Таким образом, эффект gif не работает во время анимации позиции UIImageView. Мой вопрос: как сделать так, чтобы UIImageView циклически перебирал массив изображений, пока его позиция анимируется?


person pasawaya    schedule 15.04.2013    source источник
comment
К моему ответу добавлены детали и наглядное видео.   -  person matt    schedule 20.04.2013


Ответы (4)


Это предположение, и я вообще не тестировал эту идею, но рассматривали ли вы возможность реализации анимации изображения таким же образом, как вы анимируете позицию, с помощью CAKeyframeAnimation? Вам нужно будет построить массив из CGImage объектов из вашего UIImage массива (чтобы установить свойство values анимации ключевого кадра), но это выглядит довольно простым преобразованием:

CAKeyframeAnimation *imageAnimation = [CAKeyframeAnimation animation];
imageAnimation.calculationMode = kCAAnimationDiscrete; // or maybe kCAAnimationPaced
imageAnimation.duration = self.tileSet.constants.animationDuration;
imageAnimation.repeatCount = HUGE_VALF;
// the following method will need to be implemented to cast your UIImage array to CGImages
imageAnimation.values = [self animationCGImagesArray];
[self.playerSprite.layer addAnimation:imageAnimation forKey:@"contents"];

-(NSArray*)animationCGImagesArray {
    NSMutableArray *array = [NSMutableArray arrayWithCapacity:[self.player.animationImages count]];
    for (UIImage *image in self.player.animationImages) {
        [array addObject:(id)[image CGImage]];
    }
    return [NSArray arrayWithArray:array];
}
person Seamus Campbell    schedule 19.04.2013
comment
Как мне сохранить массив объектов CGImage в массиве? Я их просто закинул на (id)? - person pasawaya; 20.04.2013
comment
да. И вы можете получить CGImage от UIImage с [myImage CGImage]. - person Seamus Campbell; 21.04.2013
comment
Я настолько согласен с таким подходом, что полностью переписал свой ответ! - person matt; 21.04.2013
comment
Этот пример у меня не сработал. Добавление анимации ключевого кадра в uiimageview с UIimages из каталога ресурсов, а затем вызов startanimation не изменяет исходное изображение - person Nikolay Spassov; 22.10.2014
comment
Код @SeamusCampbell аварийно завершает работу, если у нас есть больше изображений (300 изображений размером 720 * 720 с размером каждого 60 КБ), любая альтернатива или идея ?? Поскольку добавление изображений в массив будет выделять много памяти, следовательно, сбой памяти !!!! - person Purushottam Sain; 21.06.2017

Я только что сделал нечто подобное. Код, который я использовал, выглядит так:

    CGRect r = ziv.frame;
    r.origin.x += WrongDistance;
    [ziv startAnimating];
    [UIView animateWithDuration:3.0 animations:^(void){
        [ziv setFrame:r];
    } completion:^(BOOL finished){

        [ziv stopAnimating];

        if (finished){
            // not canceled in flight
            if (NumWrong == MaxWrong)
                [self endOfGame:NO];
            else
                [self nextRound:self];
        }
    }];

Возможно, вы столкнулись с проблемой, потому что обе анимации находятся в одном потоке?

person Mike M    schedule 15.04.2013

Ваша «основная» проблема начинается с этой строки:

CABasicAnimation *moveAnimation = [CABasicAnimation animation];

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

Использование CAKeyframeAnimation, как предлагает Симус, является одним из способов решения проблемы: анимация по ключевым кадрам будет перерисовывать содержимое анимированного слоя несколько раз, поэтому рисование последовательных изображений для каждого ключевого кадра будет анимировать содержимое, а также положение.

person Caleb    schedule 20.04.2013

Это не лучший способ сделать спрайт. Я мог бы настоять на том, чтобы вы использовали OpenGL, но, возможно, нет необходимости заходить так далеко; вы можете сделать все это с помощью Core Animation слоя, и я думаю, вам будет лучше сделать это, чем пытаться использовать полноценный UIImageView.

Используя базовую анимацию слоя, я смог заставить этот спрайт Пакмана анимировать по экрану, открывая и закрывая рот; разве это не то, что вы имели в виду?

введите описание изображения здесь

Вот видео, показывающее анимацию!

http://www.youtube.com/watch?v=WXCLc9ww8MI

И все же фактический код, создающий анимацию, чрезвычайно прост: всего два слоя анимации (Core Animation), одна для изменяющегося изображения, другая для позиции.

Вы не должны награждать этот ответ наградой! Я сейчас просто повторяю то, что сказал Симус Кэмпбелл; Я просто немного уточню детали его ответа.

Хорошо, вот код, который генерирует фильм, указанный выше:

- (void)viewDidLoad {
    [super viewDidLoad];
    // construct arr, an array of CGImage (omitted)
    // it happens I've got 5 images, the last being the same as the first
    self.images = [arr copy];
    // place sprite into the interface
    self.sprite = [CALayer new];
    self.sprite.frame = CGRectMake(30,30,24,24);
    self.sprite.contentsScale = [UIScreen mainScreen].scale;
    [self.view.layer addSublayer:self.sprite];
    self.sprite.contents = self.images[0];
}

- (void)animate {
    CAKeyframeAnimation* anim = 
        [CAKeyframeAnimation animationWithKeyPath:@"contents"];
    anim.values = self.images;
    anim.keyTimes = @[@0,@0.25,@0.5,@0.75,@1];
    anim.calculationMode = kCAAnimationDiscrete;
    anim.duration = 1.5;
    anim.repeatCount = HUGE_VALF;

    CABasicAnimation* anim2 = 
        [CABasicAnimation animationWithKeyPath:@"position"];
    anim2.duration = 10;
    anim2.toValue = [NSValue valueWithCGPoint: CGPointMake(350,30)];

    CAAnimationGroup* group = [CAAnimationGroup animation];
    group.animations = @[anim, anim2];
    group.duration = 10;

    [self.sprite addAnimation:group forKey:nil];
}
person matt    schedule 15.04.2013
comment
Извините, я не принял. Я попытался перейти по ссылке (которая поначалу выглядела многообещающей), но у меня не получилось. Тем не менее, я попробую ваш новый код. Спасибо! - person pasawaya; 20.04.2013
comment
Просто вопрос: что такое свойство index у CALayer? - person pasawaya; 20.04.2013
comment
Это похоже на свойство sampleIndex в руководстве, на которое я указал. Обычно при изменении index подкласс CALayer перерисовывает следующее изображение в последовательности. - person matt; 20.04.2013
comment
Теперь я предоставил еще более сложный код, довольно значительно отличающийся от исходного руководства. - person matt; 20.04.2013
comment
Снова исправляем, на этот раз без подкласса слоя спрайта. - person matt; 21.04.2013
comment
Спасибо за все усилия, которые вы прилагаете к этому. Я смотрел на код и задавался вопросом, где именно происходит анимация между изображениями. - person pasawaya; 21.04.2013
comment
Хорошо, я в основном отозвал свой предыдущий ответ и переписал его, следуя примеру Симуса Кэмпбелла. Насколько я понимаю, он получает награду! Вы должны отклонить мой ответ. Его ответ правильный; Я просто заполняю детали на случай, если они вам понадобятся. - person matt; 21.04.2013
comment
Хорошо. В любом случае, спасибо за всю помощь, которую вы мне оказали. Я очень ценю это. - person pasawaya; 21.04.2013
comment
Мне очень понравилось играть и создавать свой маленький пример PacMan! - person matt; 21.04.2013