2013-03-22 10 views
8

Sto costruendo un'applicazione iOS in cui ho un requisito per il backgroundColor della vista per l'animazione attraverso una selezione di colori. Nel mio metodo viewDidLoad fondamentalmente sto sparando una catena di animazioni UIView usando il seguente.Il modo migliore per gestire una catena di animazioni con UIViewAnimations

-(void) beginFirstStageBackgroundAnimation 
{ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed: 251./255 green:203./255 blue:147./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self secondStageBackgroundAnimation]; 
        } 
    ]; 
} 

Il gestore completamento spara il secondo metodo che contiene il colore successivo ....

-(void) secondStageBackgroundAnimation 
{ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed:251./255 green:224./255 blue:96./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self thirdStageBackgroundAnimation]; 
        } 
    ]; 
} 

E così via ... questo va avanti fino a quando nel settimo di animazione chiamo [self beginFirstStageBackgroundAnimation]; nel completamento di ricominciare il processo.

Quando lascio la vista con il pulsante Indietro, in visualizzazioneDidDisappare o quando termina il timer sul display corro [self.view.layer removeAllAnimations]; per eliminare completamente le animazioni. Tuttavia, l'app funziona e funziona esattamente come previsto, ma sembra bloccarsi dopo aver abbandonato la vista e aver funzionato per un intero e anche se non so perché ancora sembra correlato a questa catena di animazione.

C'è una soluzione migliore per animare il backgroundColor della vista ogni 3 secondi con un ritardo di 3 secondi?

E lo [self.view.layer removeAllAnimations]; fa effettivamente ciò che voglio?

EDIT: Il codice in cui lascio la vista è la seguente:

-(void) backBtnPressed:(id)sender 
{ 
    [self stopAudio]; // stop audio that is playing. 
    [self.view.layer removeAllAnimations]; // remove all animations? 
    [self.navigationController popViewControllerAnimated: YES]; // pop view from stack 
} 
+0

io non sono sicuro che removeAllAnimations ferma l'animazione, è per l'animazione collegata allo strato, e non si è direttamente utilizzando l'animazione strato, ma UIView animazione ... in ogni caso non dovrebbe bloccarsi, si potrebbe chiamare anche senza chiamare alcuna animazione. qual è il tuo registro dopo un incidente? – meronix

+1

+1 il vero pericolo qui è liquidare la pila in un ciclo ogni tre secondi - fondamentalmente una grande ricorsione lenta. la risposta che hai accettato lo evita, così come il mio. sono sicuro che la risposta accettata va bene, anche se è mia preferenza attaccare con blocchi ovunque sia possibile. – danh

risposta

5

Si può provare a utilizzare CAAnimation penso che sarà più facile di gestire i colori e le animazioni

- (void)viewDidAppear:(BOOL)animated 
{ 
    [super viewDidAppear:animated]; 
    NSArray *colors = @[[UIColor greenColor], 
         [UIColor redColor], 
         [UIColor blueColor], 
         [UIColor yellowColor], 
         [UIColor orangeColor] 
         ]; 
    NSMutableArray *animations = [NSMutableArray new]; 
    float colorAnimationDuration = 3.0f; 
    for (int i = 0; i < colors.count; i++) 
    { 
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 
     animation.toValue = (id)[[colors objectAtIndex:i] CGColor]; 
     animation.duration = colorAnimationDuration; 
     animation.beginTime = i * colorAnimationDuration; 
     animation.removedOnCompletion = NO; 
     animation.fillMode = kCAFillModeForwards; 

     [animations addObject:animation]; 
    } 

    CAAnimationGroup *animationsGroup = [CAAnimationGroup new]; 
    animationsGroup.duration = colors.count * colorAnimationDuration; 
    animationsGroup.repeatCount = HUGE_VALF; 
    animationsGroup.animations = animations; 

    [self.view.layer addAnimation:animationsGroup forKey:@"myAnimations"]; 

} 

- (void)viewWillDisappear:(BOOL)animated 
{ 
    [super viewWillDisappear:animated]; 
    [self.view.layer removeAnimationForKey:@"myAnimations"]; 
} 
+0

sembra funzionare perfettamente. Apprezzo che –

-1

tenta di aggiungere un controllo all'interno di ogni metodo di animazione, in questo modo:

-(void) secondStageBackgroundAnimation 
{ 
if (self.view.superview){ 
    [UIView animateWithDuration: 3.0f 
          delay: 3.0f 
         options: UIViewAnimationOptionTransitionCrossDissolve 
        animations:^{ 
         self.view.backgroundColor = [UIColor colorWithRed:251./255 green:224./255 blue:96./255 alpha:1.0]; 
        } 
        completion:^(BOOL finished){ 
         [self thirdStageBackgroundAnimation]; 
        } 
    ]; 
} 
} 

potreste inserire il codice in cui "lasci la vista con il pulsante indietro"? il problema potrebbe essere lì ...

+0

Domanda modificata. Il codice inviato come richiesto –

7

Penso che il modo per andare è quello di rappresentare ciò che si vuole per accadere in ogni animazione parametricamente (che in questo caso è solo un colore), e quindi mantenere quei parametri in un array. L'array è come la vostra lista di cose da fare animazione:

@property(strong, nonatomic) NSArray *animationTodo; 

abbiamo anche bisogno di tenere traccia di dove ci troviamo nella lista. Utilizzare un (NS) numero scatolato in modo da poter rappresentare "non animare" come nullo, distinto da indice zero:

@property(strong, nonatomic) NSNumber *animationIndex; 

La matrice viene inizializzato con colori:

self.animationTodo = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], ... nil]; 

Ora l'animazione può essere compresso a un unico metodo:

- (void)animate { 

    if (!animationIndex) return; 
    NSInteger index = [animationIndex intValue]; 
    [UIView animateWithDuration:3.0 animations:^{ 
     self.view.backgroundColor = [animationToDo objectAtIndex:index]; 
    } completion:^(BOOL finished) { 
     NSInteger nextIndex = (index==self.animationTodo.count-1)? 0 : index+1; // advance index in a ring 
     self.animationIndex = [NSNumber numberWithInt:nextIndex]; 
     // schedule the next one in 3s 
     [self performSelector:@selector(animate) withObject:nil afterDelay:3.0]; 
    }]; 
} 

Eseguire selettore vi dichiarare il ritardo e ha anche l'effetto positivo di non procedere alla liquidazione della pila ogni volta che si avvia l'animazione successiva let.

Anche arrestare è semplice. Fallo prima che la vista scompaia e in qualsiasi altro momento desideri interrompere.

- (void)stopAnimating { 

    self.animationIndex = nil; 
    [NSObject cancelPreviousPerformRequestsWithTarget:self]; 
} 
+1

abbia appena visto questa risposta. Sono andato con la soluzione dalla risposta accettata, che funziona perfettamente per i miei bisogni. Tuttavia, anche questo è un ottimo modo e non qualcosa che avevo persino considerato. –

Problemi correlati