Метод доступа после завершения анимации UIImageView

У меня есть массив изображений, загружаемых в UIImageView, которые я анимация через один цикл. После того, как изображения были отображены, я хотел бы вызвать @selector, чтобы отклонить текущий контроллер представления. Изображения анимируются с помощью этого кода:

NSArray * imageArray = [[NSArray alloc] initWithObjects:
                        [UIImage imageNamed:@"HowTo1.png"], 
                        [UIImage imageNamed:@"HowTo2.png"],
                        nil];
UIImageView * instructions = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

instructions.animationImages = imageArray;
[imageArray release];
instructions.animationDuration = 16.0;
instructions.animationRepeatCount = 1;
instructions.contentMode = UIViewContentModeBottomLeft;
[instructions startAnimating];
[self.view addSubview:instructions];
[instructions release];

Через 16 секунд я хотел бы вызвать метод. Я просмотрел метод класса UIView setAnimationDidStopSelector:, но я не могу заставить его работать с моей текущей реализацией анимации. Любые предложения?

Спасибо.

Ответ 1

Используйте performSelector:withObject:afterDelay::

[self performSelector:@selector(animationDidFinish:) withObject:nil
    afterDelay:instructions.animationDuration];

или используйте dispatch_after:

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, instructions.animationDuration * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self animationDidFinish];
});

Ответ 2

Вы можете просто использовать эту категорию UIImageView-AnimationCompletionBlock

Взгляните на файл ReadMe в этом классе.

Добавьте файлы UIImageView + AnimationCompletion.h и UIImageView + AnimationCompletion.m в проект и импортируйте файл UIImageView + AnimationCompletion.h, где вы хотите использовать это.

Например,

NSMutableArray *imagesArray = [[NSMutableArray alloc] init];
for(int i = 10001 ; i<= 10010 ; i++)
    [imagesArray addObject:[UIImage imageNamed:[NSString stringWithFormat:@"%d.png",i]]];

self.animatedImageView.animationImages = imagesArray;
self.animatedImageView.animationDuration = 2.0f;
self.animatedImageView.animationRepeatCount = 3;
[self.animatedImageView startAnimatingWithCompletionBlock:^(BOOL success){
 NSLog(@"Animation Completed",);}];

Ответ 3

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

NSArray * imageArray = [[NSArray alloc] initWithObjects:
                    (id)[UIImage imageNamed:@"HowTo1.png"].CGImage, 
                    (id)[UIImage imageNamed:@"HowTo2.png"].CGImage,
                    nil];
UIImageView * instructions = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

//create animation
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
[anim setKeyPath:@"contents"];
[anim setValues:imageArray];

[anim setRepeatCount:1];
[anim setDuration:1];
anim.delegate = self; // delegate animationDidStop method will be called

CALayer *myLayer = instructions.layer;

[myLayer addAnimation:anim forKey:nil];

Затем просто реализуйте метод делегирования animationDidStop

Ответ 4

С помощью этого метода вы избегаете запускать таймеры, пока ImageView все еще оживляет из-за медленной загрузки изображений. Вы можете использовать как performSelector: withObject: afterDelay:, так и GCD таким образом:

[self performSelector:@selector(didFinishAnimatingImageView:)
           withObject:imageView
           afterDelay:imageView.animationDuration];

/!\ self.imageView.animationDuration должен поставить ставку до startAnimating, иначе будет 0

Затем, если -(void)didFinishAnimatingImageView: создает фоновую очередь, выполните проверку свойства isAnimating, чем остальные в главной очереди

- (void)didFinishAnimatingImageView:(UIImageView*)imageView
{

   dispatch_queue_t backgroundQueue = dispatch_queue_create("com.yourcompany.yourapp.checkDidFinishAnimatingImageView", 0);
   dispatch_async(backgroundQueue, ^{

       while (self.imageView.isAnimating)
           NSLog(@"Is animating... Waiting...");

       dispatch_async(dispatch_get_main_queue(), ^{

          /* All the rest... */

       });

   });

}

Ответ 5

Вы можете создать таймер для запуска после продолжительности анимации. Обратный вызов может обрабатывать вашу логику, которую вы хотите выполнить после завершения анимации. В своем обратном вызове обязательно проверьте статус анимации [UIImageView isAnimating] на случай, если вам нужно больше времени, чтобы завершить анимацию.

Ответ 6

в ImageView.m

- (void) startAnimatingWithCompleted:(void (^)(void))completedHandler {
if (!self.isAnimating) {
    [self startAnimating];
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, self.animationDuration * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(),completedHandler);       
}}

Ответ 7

Создана версия Swift из ответа GurPreet_Singh (UIImageView + AnimationCompletion) Мне не удалось создать расширение для UIImageView, но я считаю, что это достаточно просто для использования.

class AnimatedImageView: UIImageView, CAAnimationDelegate {

    var completion: ((_ completed: Bool) -> Void)?

    func startAnimate(completion: ((_ completed: Bool) -> Void)?) {
        self.completion = completion
        if let animationImages = animationImages {
            let cgImages = animationImages.map({ $0.cgImage as AnyObject })
            let animation = CAKeyframeAnimation(keyPath: "contents")
            animation.values = cgImages
            animation.repeatCount = Float(self.animationRepeatCount)
            animation.duration = self.animationDuration
            animation.delegate = self

            self.layer.add(animation, forKey: nil)
        } else {
            self.completion?(false)
        }
    }

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        completion?(flag)
    }
}


let imageView = AnimatedImageView(frame: CGRect(x: 50, y: 50, width: 200, height: 135))
imageView.image = images.first
imageView.animationImages = images
imageView.animationDuration = 2
imageView.animationRepeatCount = 1
view.addSubview(imageView)

imageView.startAnimate { (completed) in
     print("animation is done \(completed)")
     imageView.image = images.last
}