Метод доступа после завершения анимации UIImageView - PullRequest
12 голосов
/ 14 февраля 2012

У меня есть массив изображений, загруженных в 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:, но не могу заставить его работать с моей текущей реализацией анимации. Есть предложения?

Спасибо.

Ответы [ 7 ]

22 голосов
/ 14 февраля 2012

Используйте 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];
});
20 голосов
/ 25 января 2014

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

А для Swift версия: UIImageView-AnimationImagesCompletionBlock

Взгляните на файл 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",);}];
8 голосов
/ 02 мая 2013

Нет способа сделать это точно с UIImageView. Использование задержки будет работать большую часть времени, но после запуска startAnimating может возникнуть некоторая задержка, прежде чем анимация появится на экране, поэтому она не точная. Вместо использования 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 голосов
/ 14 октября 2013

С помощью этого метода вы избегаете срабатывания таймеров во время анимации 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... */

       });

   });

}
3 голосов
/ 29 августа 2017

Создана версия 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
}
3 голосов
/ 14 февраля 2012

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

1 голос
/ 08 апреля 2013

в 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);       
}}
...