2012-03-02 13 views
13

Ho usato CAKeyframeAnimations per animare le proprietà transform.rotation e transform.translation.x di un livello, ma ho difficoltà ad animare implicitamente la proprietà transform. Ho un livello che deve animare tra due stati e l'interpolazione predefinita di CABasicAnimation è totalmente errata e non segue il percorso che voglio. CAKeyframeAnimazione in soccorso, o almeno così pensavo. Qualsiasi tentativo di animare transform utilizzando un risultato CAKeyframeAnimation nella vista esegue immediatamente lo snap alla trasformazione finale mentre vengono eseguite le altre animazioni. Se rimuovo la prima metà della seguente funzione e lascia che i miei eventi di "trasformazione" utilizzino il CABasicAnimation in fondo, si anima bene, anche se con trasformazioni errate interpolate lungo la strada.Come faccio ad animare CATransform3Ds con CAKeyframeAnimation?

mio strato delegato ha assunto le seguenti:

- (id <CAAction>) actionForLayer:(CALayer *)layer forKey:(NSString *)event 
{  
    if ([event isEqualToString:@"transform"]) 
    { 
     CGSize startSize = ((CALayer *)self.layer.presentationLayer).bounds.size; 
     CGSize endSize = self.layer.bounds.size; 

     CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:event]; 
     animation.duration = 0.25; 

     NSMutableArray *values = [NSMutableArray array]; 

     int stepCount = 10; 
     for (int i = 0; i < stepCount; i++) 
     { 
      CGFloat p = i/(float)(stepCount - 1); 
      CGSize size = [self interpolateBetweenSize:startSize andSize:endSize percentage:p]; 
      CATransform3D transform = [self transformForSize:size]; 
      [values addObject:[NSValue valueWithCATransform3D:transform]]; 
     } 

     animation.values = values; 
     return animation; 
    } 

    // All other animations use this basic animation 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event]; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
    animation.removedOnCompletion = YES; 
    animation.fillMode = kCAFillModeForwards; 
    animation.duration = 0.25; 
    return animation; 
} 

la mia trasformazione è una conversione seguita da una rotazione, ma penso un'animazione di gruppo con le animazioni dei fotogrammi chiave separati animare attraverso una traduzione e una rotazione si tradurrebbe in folle cittadina. Ho confermato che la dimensione & transform è corretta per tutti i valori di p che passo però, e p varia strettamente da 0 a 1.

Ho provato a impostare una funzione di temporizzazione non predefinita, ho provato a impostare una serie di funzioni di temporizzazione, ho omesso il keyTImes, ho impostato un repeatCount di 0, rimossoOnCompletion = YES e un fillMode di forward e questo non ha avuto alcun effetto. Non sto creando correttamente l'animazione del fotogramma chiave di trasformazione?

+1

Potresti forse chiarire l'effetto esatto che stai cercando di ottenere? Lo descrivi come una traduzione seguita da una rotazione, ma dal tuo codice sembra che anche i limiti si animino - è corretto?Vuoi che il livello si sposti, quindi ruoti, con i limiti che crescono o si restringono continuamente in entrambe le fasi dell'animazione di movimento/rotazione? – GSnyder

+0

Perché deve essere implicito? Questo codice sembra hacky. Se vuoi un controllo a grana fine, perché non creare l'animazione e aggiungerla direttamente al livello, che dici di aver già lavorato? Restituisci anche 'nil' da quel metodo delegato se vuoi che le cose usino la loro animazione predefinita. –

risposta

0

Questa tecnica ha funzionato in iOS 3, ma sembrava essere rotto in iOS 5.0.

5.1 "magicamente" risolto, sembrava un errore in iOS 5.0. Registrerei un radar, ma ora funziona in 5.1.

@Gsnyder: alcuni background: sto sperimentando con l'interfaccia utente Clear-like (per qualcosa completamente non correlato a Clear) e ho inventato questo: http://blog.massivehealth.com/post/18563684407/clear. Questo dovrebbe spiegare la necessità di ruotare & translate.

Da allora ho creato una transizione dell'otturatore che suddivide una vista in N layer (invece di solo 2) che appare in questo modo se vista lateralmente: /////.

Il mio codice non sta animando i limiti, sta utilizzando la dimensione di ogni passaggio per determinare la trasformazione necessaria.

@ Paul.s: Implicito mi consente di mantenere questa astrazione all'interno della classe layer stessa senza inquinare il controller della vista che la possiede. Il controller della vista dovrebbe semplicemente cambiare i limiti e il livello dovrebbe spostarsi in modo appropriato. Non sono un fan dei controller di vista con dozzine di animazioni personalizzate quando le visualizzazioni stesse possono gestirle.

Ho bisogno di utilizzare un'animazione di fotogrammi chiave perché l'animazione di default tra le trasformazioni di livello/e _ si animano attraverso angoli errati in modo che i /// \ strati non si allineino lungo la trasformazione. Le animazioni dei fotogrammi chiave assicurano che i bordi siano allineati correttamente mentre sono tutti animati.

Sto considerando questo chiuso, questo sembra essere un bug in iOS 5.0 e da allora è stato risolto. Grazie a tutti.

0
(void)animateViewWith3DCurrentView:(UIView *)currentView withPoing:(CGPoint)movePoint 
{ 
    //flip the view by 180 degrees in its place first. 
    currentView.layer.transform =   CATransform3DRotate(currentView.layer.transform,myRotationAngle(180), 0, 1, 0); 

    //set the anchor point so that the view rotates on one of its sides. 
    currentView.layer.anchorPoint = CGPointMake(0.5, 0.5); 

    //Set up scaling 

    CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey]; 

    //we are going to fill the screen here. So 423,337 
    [resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(423, 337)]]; 
    resizeAnimation.fillMode   = kCAFillModeForwards; 
    resizeAnimation.removedOnCompletion = NO; 

    // Set up path movement 

    UIBezierPath *movePath = [UIBezierPath bezierPath]; 

    //the control point is now set to centre of the filled screen. Change this to make the path different. 
    // CGPoint ctlPoint  = CGPointMake(0.0, 0.5); 
    CGPoint ctlPoint  = CGPointMake(1024/2, 768/2); 

    //This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here. 

    // Set here to get the accurate point.. 
    [movePath moveToPoint:movePoint]; 

    //The anchor point is going to end up here at the end of the animation. 
    [movePath addQuadCurveToPoint:CGPointMake(1024/2, 768/2) controlPoint:ctlPoint]; 

    CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement]; 

    moveAnim.path    = movePath.CGPath; 
    moveAnim.removedOnCompletion = YES; 

    // Setup rotation animation 

    CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation]; 
    //start from 180 degrees (done in 1st line) 
    CATransform3D fromTransform  = CATransform3DMakeRotation(myRotationAngle(180), 0, 1, 0); 
    //come back to 0 degrees 
    CATransform3D toTransform   = CATransform3DMakeRotation(myRotationAngle(0), 0, 1, 0); 

    //This is done to get some perspective. 
    CATransform3D persp1 = CATransform3DIdentity; 
    persp1.m34 = 1.0/-3000; 

    fromTransform = CATransform3DConcat(fromTransform, persp1); 
    toTransform = CATransform3DConcat(toTransform,persp1); 

    rotateAnimation.toValue    = [NSValue valueWithCATransform3D:toTransform]; 
    rotateAnimation.fromValue   = [NSValue valueWithCATransform3D:fromTransform]; 
    //rotateAnimation.duration   = 2; 
    rotateAnimation.fillMode   = kCAFillModeForwards; 
    rotateAnimation.removedOnCompletion = NO; 


    // Setup and add all animations to the group 

    CAAnimationGroup *group = [CAAnimationGroup animation]; 

    [group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]]; 

    group.fillMode   = kCAFillModeForwards; 
    group.removedOnCompletion = NO; 
    group.duration   = 0.7f; 
    group.delegate   = self; 

    [group setValue:currentView forKey:kGroupAnimation]; 

    [currentView.layer addAnimation:group forKey:kLayerAnimation]; 
} 
Problemi correlati