2012-04-18 10 views
5

La mia app utilizza CALayer per disegnare viste. Più precisamente, utilizza il metodo drawLayer:inContext: su un sottolivello del livello superiore di UIView. Questo è un buon modo per ottenere l'animazione "implicita" dei disegni consecutivi di drawLayer:inContext: che si dissolvono a vicenda nel tempo. Le animazioni in dissolvenza avvengono abbastanza velocemente, forse in 0,25 secondi, ma per modificarne la durata, è sufficiente implementare un altro metodo delegato chiamato actionForLayer:forKey:. In questo esempio di implementazione perfettamente funzionante qui la durata predefinita è allungato a 2,0 secondi:CALayer dissolvenza dal valore corrente

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event 
{ 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event]; 
    animation.duration = 2.0; 
    return animation; 

    // or return nil for the default duration. 
} 

On per la questione a portata di mano.

Se chiami [sublayer setNeedsDisplay] più velocemente di quanto le dissolvenze abbiano il tempo di completare, con ogni nuova dissolvenza vedrai un salto improvviso. A giudicare dall'aspetto, la dissolvenza in corso viene annullata e lo stato finale viene utilizzato come punto di partenza della nuova dissolvenza. Questo potrebbe non essere molto sorprendente, ma il risultato visivo è piuttosto indesiderato.

Considerare lo scenario di una dissolvenza di dieci secondi da nero a bianco, con un'altra dissolvenza, a nero, attivata cinque secondi dopo l'inizio. L'animazione inizierà a sbiadire dal nero al bianco, ma quando è a un "mezzo grigio" salta al bianco completo prima di sbiadire di nuovo in nero.

C'è un modo per evitare che ciò accada? Posso far sbiadire il livello dal grigio al nero? Esiste un equivalente di disegno CALayer del UIViewAnimationOptionBeginFromCurrentState (utilizzato nelle animazioni di UIView)?

Cheers.

risposta

2

Un layer è solo una rappresentazione visiva di ciò che il livello dovrebbe essere simile come anima. In CA quando si anima da uno stato a un altro, l'intero stato del livello cambia immediatamente. Viene creato un livello di presentazione e viene visualizzata l'animazione; al termine dell'animazione, il livello effettivo viene lasciato in posizione alla fine.

Quindi, la mia ipotesi è che quando si desidera passare da uno stato a un altro e l'animazione corrente non è ancora completata, è necessario acquisire lo stato corrente dell'animazione e quindi utilizzarlo come punto di partenza punto per la tua prossima animazione.

Il problema sta nel non essere in grado di modificare l'animazione corrente di un livello.

Nel seguente post acquisisco lo stato corrente di un'animazione, lo imposto come stato corrente per il livello e lo utilizzo come valore iniziale da cui animare. Il post applica questa tecnica alla velocità/durata di un'animazione, ma può anche essere applicata al tuo scenario.

https://stackoverflow.com/a/9544674/1218605

+1

P.S. Questo post mi ha aiutato a trovare un bug nella mia API che sto sviluppando ... Grazie. –

+0

E il tuo post mi ha aiutato a sistemare l'animazione, grazie! – epologee

1

Sono un po 'perplesso anche su questo.

Si è dimenticato di specificare la modalità di riempimento kCAFillModeForwards. C'è più informazioni su questo in the reference docs.

Ad esempio, ho ottenuto che questo funzioni senza lo snap, anche se non sto modificando la durata.

@implementation FadingLayer 

- (void)fadeOut {  
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 
    animation.fillMode = kCAFillModeForwards; 
    animation.fromValue = (id)[UIColor redColor].CGColor; 
    animation.toValue = (id)[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.0].CGColor; 
    animation.removedOnCompletion = FALSE; 
    animation.delegate = self;  
    [self addAnimation:animation 
        forKey:@"test"]; 
} 

- (void)fadeIn { 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"]; 
    animation.fillMode = kCAFillModeForwards; 
    animation.fromValue = (id)[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.0].CGColor; 
    animation.toValue = (id)[UIColor redColor].CGColor; 
    animation.removedOnCompletion = FALSE; 
    animation.delegate = self;  
    [self addAnimation:animation 
        forKey:@"test"]; 
} 

@end 

probabilmente si vorrà per animare a custom property comunque.

Spero che questo aiuti: animazione/

+0

Poiché sto utilizzando 'drawLayer: inContext:' di cui la dissolvenza è animata implicitamente, l'impostazione della proprietà kCAFillModeForwards non è di aiuto. Grazie per aver provato! – epologee

0

ho voluto ottenere la stessa cosa con un'animazione di zoom di un albero layer. Ho un equivalente chiave zoom in/out dove l'utente può ingrandire l'albero del livello di conseguenza. Tuttavia, se l'utente preme l'equivalente del tasto dello zoom in rapida successione, ci sarà uno snap-back temporaneo ai valori prima dell'inizio dell'animazione, poiché l'animazione precedente non era ancora completata.

Alla fine del codice di animazione, l'esecuzione di una sola [CATransaction commit] impone il commit di tutte le transazioni in sospeso al modello di livello prima dell'inizio dell'animazione successiva e ha risolto il problema.

La documentazione dice:

+ commettere

impegnare tutte le modifiche apportate durante la transazione corrente.

Dichiarazione

+ (nulli) impegna

Considerazioni particolari

solleva un'eccezione se non esiste alcun transazione corrente.

Tuttavia, testare questo con molti messaggi [CATransaction commit] in successione in realtà non genera un'eccezione. Ho usato la stessa tecnica per mettere a tacere gli avvertimenti della forma:

Core Animation: avvertimento, filo cancellato con uncommitted CATransaction;

in una NSOperazione il cui thread di esecuzione termina prima delle animazioni di livello. Potrebbe essere che Apple abbia modificato questo comportamento nelle recenti versioni del sistema operativo in modalità no-op (che sarebbe molto più sicura) se non esiste alcuna transazione corrente, senza aggiornare la documentazione.