2011-01-18 21 views
12

Per un effetto di animazione perfettamente adatto a un approccio di gruppo di animazione come mostrato in Brad Larson's answer here, ho bisogno dell'animazione per procedere in base agli input. Specificamente tocco e posizione dei tocchi rilevati. È facile da gestire i touchMoved: e per impostare la posizione degli elementi per ogni tocco, ma non è semplice come l'approccio dell'animazione core.Animazione iPhone basata su valori di input (tocchi) non ora

Immagina un marmo su una pista scanalata. Voglio spingere il marmo lungo qualsiasi posizione a qualsiasi velocità in una direzione o nell'altra. L'animazione deve fare qualcosa del genere, spostando un elemento visivo lungo un percorso in risposta ai tocchi. CAKeyframeAnimation ha esattamente il bit del percorso ma sembra voler sempre basare la transizione da frame a frame sul tempo trascorso, non su qualsiasi altro fattore, e in una direzione.

Aggiornamento 31 gennaio - Grazie a tutti per le risposte finora, ma nessuna risolve il problema. Ho un menu circolare che viene trascinato per selezionare un'opzione. Tutto ciò ha bisogno di muoversi insieme e ho lavorato attorno ad esso usando una vista che ha una trasformata di rotazione applicata e la trasformata di rotazione inversa applicata alle sue sottoview, in modo che tutte le icone ruotino con l'appropriato orientamento della ruota panoramica. Sembra davvero meglio quando le icone sono animate lungo un percorso un po 'ovoide però ... la descrizione del marmo è un tentativo di chiarire quello che sto cercando di fare. Meglio forse immaginare dei magneti orientati a respingere tutti i viaggi in un solco: muoverne uno ei suoi vicini si muoveranno troppo ma non necessariamente nella direzione in cui il magnete trascinato si muove mentre il percorso si curva.

In questo momento il problema è quello di seguire un semplice percorso creato con un cerchio ma mi piacerebbe davvero sapere come animare gli oggetti lungo un percorso arbitrario, posizione controllata semplicemente dal tocco senza calcoli che coinvolgono velocità o direzione.

+0

Hmm, questa è diventata una domanda popolare. La risposta di Pivot è corretta e ha funzionato bene per me nel codice scritto dalla domanda. –

risposta

7

Potrebbe essere possibile utilizzare lo hierarchical nature of timelines negli alberi di livello per ottenere ciò che si sta cercando. Gli oggetti che implementano CAMediaTiming, che includono sia CAAnimation e CALayer, ereditano un orario dal genitore, che possono modificare (tramite ridimensionamento, spostamento e ripetizione) e propagarsi ai figli. Impostando la proprietà speed di un livello su 0.0 e regolando manualmente la proprietà timeOffset, è possibile disaccoppiare quel livello (e tutti i relativi sottolivelli) dalla consueta nozione di tempo.

Cosa faresti nel tuo caso è definire le animazioni per tutte le voci di menu per animare la loro posizione lungo il desiderato CGPath di tanto t - t , con l'appropriato timeOffset su ogni animazione per mantenere i tuoi articoli opportunamente distanziati. Si noti che uno beginTime di 0.0 su un'animazione viene in genere interpretato come a partire dal momento in cui l'animazione è stata aggiunta al suo livello, quindi se si desidera t essere 0.0, sarà probabilmente necessario impostarlo su un piccolo epsilon> 0.0.

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; 
animation.beginTime = 1e-100; 
animation.duration = 1.0; 
animation.fillMode = kCAFillModeBoth; 
animation.removedOnCompletion = NO; 
animation.path = path; 
animation.calculationMode = kCAAnimationPaced; 
animation.timeOffset = timeOffset; 

Farebbe quindi imposta la proprietà speed-0,0 su un livello superiore (contenente solo queste voci di menu) e aggiornare la sua timeOffset a valori compresi tra t e t in risposta ai tuoi eventi di tocco.

Questo approccio presenta due potenziali avvertimenti. Poiché hai trascurato la natura del tempo su questa sottostruttura di livello, probabilmente non sarai in grado di animare altre proprietà contemporaneamente. Inoltre, se vuoi un comportamento di coasting per un colpo rapido, probabilmente dovrai animare il tempo in avanti da solo.

+0

Ottima idea! Lo accetto perché darà il livello di controllo di cui ho bisogno anche se non è esattamente un'animazione vincolante per toccare la posizione. Dovrebbe essere possibile manipolare timeOffset per renderlo molto vicino alla stessa cosa. –

+0

Se la relazione tra la posizione del tocco e l'avanzamento dell'animazione è lineare, è possibile scegliere il tempo di inizio e la durata delle animazioni in modo tale da poter passare il componente pertinente della posizione tattile come timeOffset e disporre della relazione tempo-avanzamento della Core Animation per applicare tale relazione per te. – Pivot

1

Se si utilizza iOS 4.0 o versione successiva, è possibile utilizzare new block based class methods per avviare modifiche animabili agli oggetti view. Così dal vostro evento di tocco è possibile avviare un cambiamento animatable alle proprietà della vista:

[UIView animateWithDuration:1.0 animations:^{ 
    yourView.alpha = 0.0; // fade out yourView over 1 second 
}]; 

N.B. Questo potrebbe facilmente essere una modifica ad un'altra proprietà sulla vista, come la sua posizione. È possibile animare le seguenti proprietà sulla vista in questo modo:

@property frame 
@property bounds 
@property center 
@property transform 
@property alpha 
@property backgroundColor 
@property contentStretch 

Se ci si rivolge versioni precedenti di iOS è necessario utilizzare UIView beginAnimations e commitAnimations metodi per creare un blocco di animazione:

[UIView beginAnimations:nil context:context]; 
[UIView setAnimationDuration:1.0]; 
yourView.alpha = 0.0; 
[UIView commitAnimations]; 

Questa roba funziona davvero bene e una volta che inizi a usarlo, dovrai stare attento a non diventare dipendente. ;)

Aggiornamento per un commento:

È possibile associare la posizione del marmo alla posizione del tocco dell'evento. Una volta ottenuto l'evento touchesEnded, è possibile animare la posizione del marmo utilizzando un blocco di animazione.

+0

Sì, ma il problema è che non voglio avere nulla a che fare con la durata. Pensa al marmo. Se non faccio niente, non fa nulla. Se lo spingo lentamente, si muove lentamente, se veloce poi si muove velocemente. Se smetto di spingerlo all'improvviso dopo averlo spostato velocemente, dovrebbe continuare a ruotare finché non rallenta e si ferma. Sembra che l'approccio temporale non permetta questo. Ho delle belle animazioni fluide che si verificano con CAKeyframeAnimation, ma non posso controllarlo se non per impostarlo in esecuzione e per metterlo a suo agio/disintegrarlo. –

+0

C'è ancora un problema. La posizione degli oggetti non è la posizione del tocco, devono rimanere in un percorso. Il tratto del tocco conferisce movimento agli oggetti solo quando i tocchi si verificano nella vista corretta. Gli oggetti devono seguire un percorso.Anche calcolare la posizione e farlo in modo ovvio non è abbastanza semplice, specialmente quando il calcolo della posizione diventa costoso o su dispositivi iOS meno recenti. –

+0

@ adam-eberbach Ah! Vedo il tuo punto. È l'interpolazione tra gli eventi touche che sta causando problemi. Ci penserò. Sicuramente non banale :) – RedBlueThing

1

velocità = distanza/tempo. Puoi provare dando un ritardo in base ai tocchi spostati e al tempo. È possibile calcolare il tempo tra i touchBegan e tocca i metodi Ended.

0

Non sono del tutto sicuro di capire esattamente cosa vuoi fare ma ... Perché non disegnare il marmo ovunque sia il dito dell'utente? Nessuna animazione richiesta. Se si desidera mantenere il marmo in movimento dopo che l'utente ha lasciato andare, è necessario mantenere un concetto di quantità di moto e utilizzarlo per animare il marmo rallentando. Puoi utilizzare CoreAnimation per questo o un timer.

0

Vorrei fare un calcolo della velocità nei tocchi spostati e aggiungerlo a una variabile locale che un blocco può mutare tramite un timer.

in altre parole, nei tocchi spostati eseguire un calcolo della velocità tenendo presente la direzione di una velocità precedente. Alla fine dei tocchi, spara un blocco che traduce il "marmo" che decompone la velocità mentre sei in disuso. Se l'utente sposta nuovamente il marmo, modifica la variabile locale, questo a sua volta accelera l'animazione del marmo o lo rallenta/cambia direzione in base alla direzione del tocco.

Problemi correlati