2013-01-30 3 views
9

Sto tentando di ritardare l'animazione dell'opacità e della posizione del livello di 3 secondi utilizzando setBeginTime. Ho chiamato il layer boxLayer. L'animazione sta andando bene tuttavia durante i primi 3 secondi (il layer non dovrebbe ancora essere mostrato) il layer viene visualizzato nella sua posizione finale e opacità. Non dovrebbe. L'animazione di gruppo non risolve il problema. Qualcuno potrebbe aiutare? Vedere codice qui sotto:Cercando di ritardare CABasicAnimazione posizione e opacità del livello di 3 secondi ma

// Create an animation that will change the opacity of a layer 
CABasicAnimation *fader = [CABasicAnimation animationWithKeyPath:@"opacity"]; 


// It will last 1 second and will be delayed by 3 seconds 
[fader setDuration:1.0]; 
[fader setBeginTime:CACurrentMediaTime()+3.0]; 


// The layer's opacity will start at 0.0 (completely transparent) 
[fader setFromValue:[NSNumber numberWithFloat:startOpacity]]; 

// And the layer will end at 1.0 (completely opaque) 
[fader setToValue:[NSNumber numberWithFloat:endOpacity]]; 

// Add it to the layer 
[boxLayer addAnimation:fader forKey:@"BigFade"]; 

// Maintain opacity to 1.0 JUST TO MAKE SURE IT DOES NOT GO BACK TO ORIGINAL OPACITY 
[boxLayer setOpacity:endOpacity]; 


// Create an animation that will change the position of a layer 
CABasicAnimation *mover = [CABasicAnimation animationWithKeyPath:@"position"]; 

// It will last 1 second and will be delayed by 3 seconds 
[mover setDuration:1.0]; 
[mover setBeginTime:CACurrentMediaTime()+3.0]; 

// Setting starting position 
[mover setFromValue:[NSValue valueWithCGPoint:CGPointMake(startX, startY)]]; 

// Setting ending position 
[mover setToValue:[NSValue valueWithCGPoint:CGPointMake(endX, endY)]]; 

// Add it to the layer 
[boxLayer addAnimation:mover forKey:@"BigMove"]; 

// Maintain the end position at 400.0 450.0 OTHERWISE IT IS GOING BACK TO ORIGINAL POSITION 
[boxLayer setPosition:CGPointMake(endX, endY)]; 
+0

come di fare un metodo come [auto performSelector: @selector (methodName) withObject: nil afterDelay: 3.0f]; o utilizzando sleep(); –

+0

Il mio problema non è l'animazione ritardata, ma piuttosto il fatto che il livello viene visualizzato prima che inizi l'animazione ritardata. – Armand

risposta

17

Il problema è che si sta impostando le proprietà di boxLayerposition e di opacity ai loro valori finali. È necessario:

  1. Impostare le boxLayer proprietà ai loro valori iniziali, non i loro valori di fine (questo è il motivo per cui si sta cominciando nel finale di posizione/opacità ... di solito se l'animazione inizia immediatamente, questo non è un problema, ma poiché stai differendo l'inizio, usare le posizioni finali è problematico);

  2. Per i vostri due animazioni, è necessario cambiare removedOnCompletion-NO e fillMode a kCAFillModeForwards (questo è il modo corretto per evitare che si ritornare alla posizione originale dopo il completamento).

Così:

// Create an animation that will change the opacity of a layer 
CABasicAnimation *fader = [CABasicAnimation animationWithKeyPath:@"opacity"]; 

// It will last 1 second and will be delayed by 3 seconds 
[fader setDuration:1.0]; 
[fader setBeginTime:CACurrentMediaTime()+3.0]; 

// The layer's opacity will start at 0.0 (completely transparent) 
[fader setFromValue:[NSNumber numberWithFloat:startOpacity]]; 

// And the layer will end at 1.0 (completely opaque) 
[fader setToValue:[NSNumber numberWithFloat:endOpacity]]; 

// MAKE SURE IT DOESN'T CHANGE OPACITY BACK TO STARTING VALUE  
[fader setRemovedOnCompletion:NO]; 
[fader setFillMode:kCAFillModeForwards]; 

// Add it to the layer 
[boxLayer addAnimation:fader forKey:@"BigFade"]; 

// SET THE OPACITY TO THE STARTING VALUE 
[boxLayer setOpacity:startOpacity]; 

// Create an animation that will change the position of a layer 
CABasicAnimation *mover = [CABasicAnimation animationWithKeyPath:@"position"]; 

// It will last 1 second and will be delayed by 3 seconds 
[mover setDuration:1.0]; 
[mover setBeginTime:CACurrentMediaTime()+3.0]; 

// Setting starting position 
[mover setFromValue:[NSValue valueWithCGPoint:CGPointMake(startX, startY)]]; 

// Setting ending position 
[mover setToValue:[NSValue valueWithCGPoint:CGPointMake(endX, endY)]]; 

// MAKE SURE IT DOESN'T MOVE BACK TO STARTING POSITION 
[mover setRemovedOnCompletion:NO]; 
[mover setFillMode:kCAFillModeForwards]; 

// Add it to the layer 
[boxLayer addAnimation:mover forKey:@"BigMove"]; 

// SET THE POSITION TO THE STARTING POSITION 
[boxLayer setPosition:CGPointMake(startX, startY)]; 

Personalmente, penso che si sta facendo un sacco di lavoro per qualcosa che è fatto molto più facilmente con l'animazione basata su blocchi sulla vista (ai fini di questa dimostrazione, presumo che il tuo boxLayer sia un CALayer per un controllo chiamato box). Non hai bisogno di Quartz 2D, o, se lo si fa in questo modo:

box.alpha = startOpacity; 
box.frame = CGRectMake(startX, startY, box.frame.size.width, box.frame.size.height); 

[UIView animateWithDuration:1.0 
         delay:3.0 
        options:0 
       animations:^{ 
        box.alpha = endOpacity; 
        box.frame = CGRectMake(endX, endY, box.frame.size.width, box.frame.size.height); 
       } 
       completion:nil]; 
+1

Il mio problema non è l'animazione ritardata di per sé. Che funzioni. Il mio problema è che il livello da animare (spostato e sbiadito) appare durante 3 secondi prima che sia animato. – Armand

+1

Sì. Esattamente come hai detto Rob. È "inizia visibile per 3 secondi, quindi scompare e lentamente scompare e si anima nel secondo successivo". Ho creato il livello prima del blocco che ho postato. Ho pensato che sarebbe stato troppo lungo per postare tutto. È come se fosse possibile ritardare l'animazione del livello mentre lo si visualizza per i primi secondi o posso ritardare la visualizzazione del livello mentre non si verificano animazioni. Divertente. Sto usando metodi come setBeginTime e Duration. Non eseguire il caricamento automatico o AnimateWithDuration. Qualche idea? – Armand

+0

@ user1915931 Anche se penso che sia molto più semplice utilizzare l'animazione basata sui blocchi delle viste, ho aggiornato la mia risposta anche con la risposta 'CABasicAnimation', se hai il coraggio di animare i livelli. – Rob

0

Questo articolo spiega bene il motivo per cui non si dovrebbe usare removedOnCompletion con FILLMODE https://www.objc.io/issues/12-animations/animations-explained/

Nel mio caso sto animando il livello di una vista che funziona come una navigazione ma ritardando un'animazione di rimbalzo che si trova all'interno di quella vista; HO BISOGNO DI ENTRAMBI QUESTE POSIZIONI AGGIORNATE SULLO STRATO poiché possono essere eliminate e mostrate di nuovo. Utilizzando removedOnCompletion non aggiornerà il valore del livello una volta che l'animazione completa

Il modo in cui lo faccio è aggiornare lo strato in un blocco di completamento CATransaction

CATransaction.setCompletionBlock { 
    // update the layer value 
} 

CATransaction.begin() 

// setup and add your animation 

CATransaction.commit() 
0

Per utilizzare beginTime si dovrebbe fare necessaria la configurazione del vostro oggetto animazione e set fillMode a kCAFillModeBackwards come

zoomAnimation.fillMode = kCAFillModeBackwards; 

che è detto nella documentazione di Apple:

Utilizzare la proprietà beginTime per impostare l'ora di inizio di un'animazione. Normalmente, le animazioni iniziano durante il prossimo ciclo di aggiornamento. È possibile utilizzare il parametro beginTime per ritardare l'avvio di animazione di alcuni secondi. Il modo di concatenare due animazioni insieme è impostare l'ora di inizio di un'animazione in modo che corrisponda all'ora di fine dell'altra animazione. Se si ritarda l'avvio di un'animazione, si potrebbe anche voler impostare la proprietà fillMode su kCAFillModeBackwards. Questa modalità di riempimento fa sì che il livello visualizzi il valore iniziale dell'animazione, anche se l'oggetto livello nella struttura del livello contiene un valore diverso. Senza questa modalità di riempimento, si vedrebbe un salto al valore finale prima che l'animazione inizi l'esecuzione. Sono disponibili anche altre modalità di riempimento.

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreAnimation_guide/AdvancedAnimationTricks/AdvancedAnimationTricks.html#//apple_ref/doc/uid/TP40004514-CH8-SW2

Inoltre, dalla domanda di Rob:

Per i vostri due animazioni, è necessario cambiare removedOnCompletion a NO e FILLMODE a kCAFillModeForwards (questo è il modo corretto per evitare che un ritorno torna alla posizione originale al completamento).

è una sorta di dichiarazione controversa, perché:

Una volta che l'animazione viene rimosso, il livello di presentazione cadrà indietro ai valori del livello di modello, e dato che non abbiamo mai modificato quello strato di posizione, la nostra astronave riappare esattamente dove è iniziata. Esistono due modi per risolvere questo problema:

Il primo approccio consiste nell'aggiornare la proprietà direttamente sul livello del modello. Questo è l'approccio consigliato, poiché rende l'animazione completamente opzionale.

In alternativa, è possibile indicare all'animazione di rimanere nel suo stato finale impostando la proprietà fillMode su kCAFillModeForwards e impedendo che venga rimossa automaticamente impostando removeOnCompletion su NO. Tuttavia, è buona norma mantenere sincronizzati il ​​modello e i livelli di presentazione, , pertanto questo approccio deve essere utilizzato con attenzione.

Da https://www.objc.io/issues/12-animations/animations-explained/