2015-06-13 5 views
11

Quindi, sono abbastanza nuovo per la programmazione iOS e ho ereditato un progetto da un ex collaboratore. Stiamo costruendo un'app che contiene un'interfaccia utente di gauge. Quando i dati arrivano, vogliamo ruotare senza problemi il nostro "layer" (che è un'immagine di un ago) dall'angolo corrente a un nuovo angolo di mira. Ecco quello che abbiamo, che ha funzionato bene con i dati lento:come reimpostare/riavviare un'animazione e farla apparire continua?

-(void) MoveNeedleToAngle:(float) target 
{ 
    static float old_Value = 0.0; 
    CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation"); 
    [rotateCurrentPressureTick setDelegate:self]; 
    rotateCurrentPressureTick.fromValue = [NSSNumber numberWithFloat:old_value/57.2958]; 
    rotateCurrentPressureTick.removedOnCompletion=NO; 
    rotateCurrentPressureTick.fillMode=kCAFillModeForwards; 
    rotateCurrentPressureTick.toValue=[NSSNumber numberWithFloat:target/57.2958]; 
    rotateCurrentPressureTick.duration=3; // constant 3 second sweep 

    [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"]; 
    old_Value = target; 
} 

Il problema è che abbiamo un nuovo schema di dati in cui i nuovi dati possono entrare (ed il metodo di cui sopra detta) più velocemente, prima che l'animazione è completa . Quello che sta succedendo penso che l'animazione venga riavviata dal vecchio target al nuovo target, il che lo rende molto nervoso.

Così mi chiedevo come modificare la funzione di cui sopra per aggiungere un comportamento continuo/riavviabile, come segue:

  1. Controllare se l'animazione corrente è in corso e
  2. Se è così, capire dove la angolo di animazione corrente è, e quindi
  3. Cancellare la corrente e iniziare una nuova animazione dalla rotazione attuale alla nuova rotazione bersaglio

e 'possibile costruire che essere deve svolgere la suddetta funzione?

Grazie. Scusate se la domanda sembra non informata, ho studiato e capito gli oggetti/metodi di cui sopra, ma non sono un esperto.

risposta

3

Sì, è possibile farlo utilizzando il metodo esistente, se si aggiunge questo po 'di magia:

- (void)removeAnimationsFromView:(UIView*)view { 
     CALayer *layer = view.layer.presentationLayer; 
     CGAffineTransform transform = layer.affineTransform; 
     [layer removeAllAnimations]; 
     view.transform = transform; 
    } 

Il livello di presentazione incapsula lo stato attuale dell'animazione. La vista stessa non porta le proprietà dello stato di animazione, in pratica quando si imposta uno stato di fine animazione, la vista acquisisce tale stato non appena si attiva l'animazione. È il livello di presentazione che si "vede" durante l'animazione.

Questo metodo acquisisce lo stato del livello di presentazione nel momento esatto in cui si annulla l'animazione e quindi applica tale stato alla vista.

Ora è possibile utilizzare questo metodo nel metodo di animazione, che sarà simile a questa:

-(void) MoveNeedleToAngle:(float) target{ 
    [self removeAnimationsFromView:imageView_Needle]; 
    id rotation = [imageView_Needle valueForKeyPath:@"layer.transform.rotation.z"]; 
    CGFloat old_value = [rotation floatValue]*57.2958; 

    // static float old_value = 0.0; 
    CABasicAnimation *rotateCurrentPressureTick = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 
    [rotateCurrentPressureTick setDelegate:self]; 
    rotateCurrentPressureTick.fromValue = [NSNumber numberWithFloat:old_value/57.2958]; 
    rotateCurrentPressureTick.removedOnCompletion=NO; 
    rotateCurrentPressureTick.fillMode=kCAFillModeForwards; 
    rotateCurrentPressureTick.toValue=[NSNumber numberWithFloat:target/57.2958]; 
    rotateCurrentPressureTick.duration=3; // constant 3 second sweep 

    [imageView_Needle.layer addAnimation:rotateCurrentPressureTick forKey:@"rotateTick"]; 

    old_value = target; 

} 

(ho fatto modifiche minime al tuo metodo: ci sono alcuni cambiamenti di stile di codifica Vorrei anche fare , ma non sono rilevanti per il tuo problema)

A proposito, ti suggerisco di alimentare il tuo metodo in radianti, non in gradi, il che significa che puoi rimuovere quelle costanti 57.2958.

1

È possibile ottenere la rotazione corrente dal livello di presentazione e impostare semplicemente l'angolo di valore. Non c'è bisogno di mantenere old_value

-(void) MoveNeedleToAngle:(float) targetRadians{ 

    CABasicAnimation *animation =[CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 
    animation.duration=5.0; 
    animation.fillMode=kCAFillModeForwards; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 
    animation.removedOnCompletion=NO; 

    animation.fromValue = [NSNumber numberWithFloat: [[layer.presentationLayer valueForKeyPath: @"transform.rotation"] floatValue]]; 
    animation.toValue = [NSNumber numberWithFloat:targetRadians]; 
    // layer.transform= CATransform3DMakeRotation(rads, 0, 0, 1); 
    [layer addAnimation:animation forKey:@"rotate"]; 
} 

Un altro modo che ho trovato (linea commentata sopra) è invece di utilizzare fromValue e toValue sufficiente impostare il livello di trasformare. Ciò produrrà la stessa animazione ma il PresentationLayer e il modello saranno sincronizzati.

Problemi correlati