2013-07-20 13 views
9

Sto provando a creare una sequenza di animazioni, ho trovato in CAAnimationGroup la classe giusta per ottenere quell'oggetto. In pratica sto aggiungendo in una vista diverse sottoview e mi piacerebbe animare la loro entrata con un effetto di rimbalzo, il fatto è che voglio vedere le loro animazioni accadere subito dopo che il precedente è finito. So che posso impostare il delegato, ma ho pensato che lo CAAnimationGroup fosse la scelta giusta.
Successivamente ho scoperto che l'animazione di gruppo può appartenere solo a un livello, ma ne ho bisogno su diversi livelli sullo schermo. Ovviamente sul livello di hosting non funziona. Alcuni suggerimenti?Animazione sequenza utilizzando CAAnimationGroup

- (void) didMoveToSuperview { 
    [super didMoveToSuperview]; 
    float startTime = 0; 
    NSMutableArray * animArray = @[].mutableCopy; 
    for (int i = 1; i<=_score; i++) { 
     NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject: self.greenLeaf]; 
     UIImageView * greenLeafImageView = [NSKeyedUnarchiver unarchiveObjectWithData: archivedData]; 
     greenLeafImageView.image = [UIImage imageNamed:@"greenLeaf"]; 
     CGPoint leafCenter = calculatePointCoordinateWithRadiusAndRotation(63, -(M_PI/11 * i) - M_PI_2); 
     greenLeafImageView.center = CGPointApplyAffineTransform(leafCenter, CGAffineTransformMakeTranslation(self.bounds.size.width/2, self.bounds.size.height)); 
     [self addSubview:greenLeafImageView]; 

     //Animation creation 
     CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"]; 
     greenLeafImageView.layer.transform = CATransform3DIdentity; 
     bounceAnimation.values = @[ 
            [NSNumber numberWithFloat:0.5], 
            [NSNumber numberWithFloat:1.1], 
            [NSNumber numberWithFloat:0.8], 
            [NSNumber numberWithFloat:1.0] 
            ]; 

     bounceAnimation.duration = 2; 
     bounceAnimation.beginTime = startTime; 
     startTime += bounceAnimation.duration; 

     [animArray addObject:bounceAnimation]; 
     //[greenLeafImageView.layer addAnimation:bounceAnimation forKey:nil]; 


    } 
    // Rotation animation 
    [UIView animateWithDuration:1 animations:^{ 
     self.arrow.transform = CGAffineTransformMakeRotation(M_PI/11 * _score); 
    }]; 
    CAAnimationGroup * group = [CAAnimationGroup animation]; 
    group.animations = animArray; 
    group.duration = [[ animArray valueForKeyPath:@"@sum.duration"] floatValue]; 
    [self.layer addAnimation:group forKey:nil]; 
} 

risposta

22

CAAnimationGroup è inteso per avere più CAAnimation sottoclassi essendo impilati insieme per formare un'animazione, ad esempio, un'animazione può eseguire una scala, l'altro si muove in giro, mentre un terzo può ruotare, non è inteso per gestione di più livelli, ma per avere più animazioni sovrapposte.

Detto questo, penso che il modo più semplice per risolvere il problema, è quello di assegnare ad ogni CAAnimation un beginTime equivalente alla somma delle durate di tutti i precedenti, per illustrare:

for i in 0 ..< 20 
{ 
    let view : UIView = // Obtain/create the view...; 
    let bounce = CAKeyframeAnimation(keyPath: "transform.scale") 

    bounce.duration = 0.5; 
    bounce.beginTime = CACurrentMediaTime() + bounce.duration * CFTimeInterval(i); 

    // ... 

    view.layer.addAnimation(bounce, forKey:"anim.bounce") 
} 

Si noti che tutti ottiene duration * i e il CACurrentMediaTime() è una necessità quando si utilizza la proprietà beginTime (è fondamentalmente un timestamp ad alta precisione per "ora", utilizzato nelle animazioni).L'intera riga potrebbe essere interpretata come now + duration * i.

deve notare, che se un CAAnimation s viene aggiunto a un CAAnimationGroup, allora il suo beginTime diventa relativo al tempo di inizio del gruppo, quindi un valore di 5.0 su un'animazione, sarebbe 5.0 secondi dopo tutto il gruppo inizia. In questo caso, non usi CACurrentMediaTime()

+0

Ottimo, grazie !!! – Andrea

2

Se si esamina the documentation, noterete che CAAnimationGroup eredita da CAAnimation, e che CAAnimation può essere assegnato a un solo CALayer. L'intento è davvero quello di semplificare la creazione e la gestione di più animazioni che desideri applicare a uno CALayer allo stesso tempo, non alle animazioni di gestione per più oggetti CALayer.

Per gestire la sequenza di animazioni differenti tra diversi CALayer o UIView oggetti, una tecnica che uso è quello di creare un NSOperation per ogni oggetto/animazione, poi gettarli in un NSOperationQueue per gestire il sequenziamento. Questo è un po 'complicato visto che devi usare il callback del completamento dell'animazione per dire allo NSOperation che è finito, ma se scrivi una sottoclasse di gestione dell'animazione di NSOperation, può essere piuttosto conveniente e ti permette di creare percorsi di sequenziamento sofisticati. Il modo a basso costo per raggiungere l'obiettivo di sequenziamento è semplicemente impostare la proprietà beginTime sull'oggetto CAAnimation (che deriva dall'adozione del protocollo CAMediaTiming) in base alle esigenze per ottenere il tempo desiderato.

Con ciò detto, ho intenzione di indicarti un codice che ho scritto e open-source per risolvere esattamente lo stesso caso d'uso che descrivi. Potresti trovarlo on github here (stesso codice incluso). Vorrei aggiungere le seguenti note:

  • Il mio codice di gestione di animazione permettere che la tua per definire l'animazione in un plist identificando la sequenza e la tempistica di immagine cambia, i cambiamenti di scala, cambiamenti di posizione, ecc In realtà è piuttosto conveniente e più pulito per regolare l'animazione in un file plist anziché in codice (motivo per cui l'ho scritto).
  • Se l'utente non è in grado di interagire con le sottoview che hai creato, in realtà è molto meglio (meno spese generali) per creare oggetti di livello che vengono aggiunti come sottostrati al livello della vista di hosting.
+0

Verificherò che sembra un approccio davvero interessante – Andrea

Problemi correlati