2012-02-14 10 views
11

Ho una serie di immagini caricate in un UIImageView che sto animando attraverso un ciclo. Dopo che le immagini sono state visualizzate, vorrei chiamare uno @selector per eliminare il controller di visualizzazione corrente. Le immagini sono animate bene con questo codice:Metodo di accesso dopo UIImageView Animation Finish

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

Dopo i 16 secondi, vorrei che venisse chiamato un metodo. Ho esaminato il metodo di classe UIViewsetAnimationDidStopSelector: ma non riesco a farlo funzionare con la mia implementazione di animazione corrente. Eventuali suggerimenti?

Grazie.

risposta

22

Uso performSelector:withObject:afterDelay::

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

o utilizzare 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]; 
}); 
+0

Sono andato con il primo metodo, grazie. –

+0

Questo metodo sembra funzionare bene, grazie rob! Ma mi chiedevo cosa sarebbe successo se per qualche ragione il calo del frame-rate dell'iPhone fosse molto. Diciamo da 30 a 15. In quel caso l'animazione non sarebbe finita quando il tempo del dispatch è terminato? – Tieme

+0

Perché pensi che la frequenza di fotogrammi che scenderà renderebbe l'animazione più lunga? Forse la vista dell'immagine perde fotogrammi se non riesce a tenere il passo. –

3

È possibile creare un timer da attivare dopo la durata dell'animazione. Il callback potrebbe elaborare la logica che si desidera eseguire al termine dell'animazione. Nella tua richiamata assicurati di controllare lo stato dell'animazione [UIImageView isAnimating] nel caso volessi più tempo per lasciare che l'animazione finisca.

1

in 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);  
}} 
8

Non v'è alcun modo per farlo proprio con UIImageView. L'utilizzo di un ritardo funzionerà la maggior parte del tempo, ma potrebbe verificarsi un certo ritardo dopo l'avvio. L'animazione viene richiamata prima che l'animazione avvenga sullo schermo, quindi non è precisa. Anziché utilizzare UIImageView per questa animazione, prova a utilizzare un CAKeyframeAnimation che chiamerà un metodo delegato al termine dell'animazione. Qualcosa in questo senso:

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

Poi basta implementare il metodo animationDidStop delegato

+0

Impossibile aggiungere CGImage all'array. –

+0

Per eliminare l'avviso causato dall'aggiunta di CGImage a un array, basta lanciarlo su id. –

+0

Risposta modificata per riflettere sopra. Vedi [apples doc] (https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CAKeyframeAnimation_class/Introduction/Introduction.html#//apple_ref/occ/instp/CAKeyframeAnimation/values). –

4

Con questo metodo si evita di timer al fuoco mentre l'ImageView è ancora animando a causa di rallentare il caricamento delle immagini. Si potrebbe utilizzare sia performSelector: withObject: afterDelay: e GCD in questo modo:!

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

/\self.imageView.animationDuration deve scommettere configurato prima startAnimating, altrimenti sarà 0

Che se -(void)didFinishAnimatingImageView: creare una coda di fondo, eseguire una verifica sulla proprietà isAnimating, che eseguirà il resto sulla coda principale

- (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... */ 

     }); 

    }); 

} 
+0

Soluzione semplice, funziona come il fascino –

20

È possibile s uso Imple questa categoria UIImageView-AnimationCompletionBlock

E per Swift versione: UIImageView-AnimationImagesCompletionBlock

dare uno sguardo su file Leggimi in questa classe ..

Aggiungere UIImageView + AnimationCompletion.h e UIImageView + AnimationCompletion.m file nel progetto e loro importazione UIImageView + AnimationCompletion.h file in cui si desidera utilizzare questo ..

Per es.

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",);}]; 
+0

Grazie! È grandioso – daspianist

+0

questa dovrebbe essere la risposta accettata – 2cupsOfTech

+0

Non riesco a capire come usare questo in swift. Dopo aver aggiunto l'intestazione di bridging, non funziona ancora. –

0

Creato Swift versione da GurPreet_Singh Risposta (UIImageView + AnimationCompletion) non ero in grado di creare un estensione per UIImageView ma credo che questo è abbastanza semplice da usare.

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 
}