2016-01-20 12 views
5

Sto imparando l'animazione e l'apri del panresponder in reazione nativo. A seguito di Animated Drag and Drop with React Native e sourceCome rendere trascinabile ricordare che si trova in React Native

Desidero estendere l'esempio in modo da poter trascinare il cerchio senza doverlo resettare. Attualmente il codice anima il cerchio tornando al centro dello schermo e fa affidamento sui valori dX/dY dei panresponders.

mia ipotesi migliore è che devo cambiare qualcosa nella onPanResponderMove

onPanResponderMove: Animated.event([null, { 
    dx: this.state.pan.x, 
    dy: this.state.pan.y, 
    }]), 

Di cosa ho bisogno di cambiare la sorgente in modo se io commento la onPanResponderRelease logica del cerchio trascina correttamente intorno allo schermo?

getTranslateTransform()?

risposta

4

La logica in onPanResponderRelease sta facendo in modo che se il draggable non è nella dropzone quando viene rilasciato, viene reimpostato su 0,0 (these are the lines causing it).

Rimuovere solo quella logica non è tutto ciò che dovresti fare. È necessario impostare l'offset e ripristinare il valore di this.state.pan in onPanResponderRelease. Per fare questo è necessario tenere traccia del valore.

In componentDidMount, aggiungere questo:

this.currentPanValue = {x: 0, y: 0}; 
this.panListener = this.state.pan.addListener((value) => this.currentPanValue = value); 

Poi, in componentWillUnmount:

this.state.pan.removeListener(this.panListener); 

Ora che avete il valore corrente, basta aggiungere questo al PanResponder:

onPanResponderRelease: (e, gestureState) => { 
    this.state.pan.setOffset({x: this.currentPanValue.x, y: this.currentPanValue.y}); 
    this.state.pan.setValue({x: 0, y: 0}); 
}, 

Sembra più complicato di quanto sia in realtà. Fondamentalmente stai semplicemente impostando l'offset da 0/0, quindi impostando il valore su 0/0 in modo che quando inizi a spostarlo di nuovo dopo averlo rilasciato prima, non ritorni a 0/0 prima di tornare a dove il dito è Inoltre si assicura che tu abbia la sua posizione corrente ... che probabilmente avrai bisogno ad un certo punto comunque.

+1

potresti approfondire cosa fa setOffset e perché è necessario? –

+0

La riga 'this.state.pan.setValue ({x: 0, y: 0});' in 'onPanResponderRelease' non è necessaria. Ottengo lo stesso risultato con o senza quella linea. Non vedo alcun effetto di questa linea. Dovrebbe essercene uno? – Andru

+1

Inoltre: nei documenti di codice di 'AnimatedImplementation.js' che scrivono usando' Animated.Value.addListener' possono causare problemi di prestazioni. Come risolverebbe questo problema con un numero maggiore di cerchi? - Un ascoltatore per ogni cerchio? – Andru

0

In realtà, l'unica cosa che è necessario modificare è la funzione onPanResponderRelease. Quello che stai facendo è applicare il delta del movimento del gesto alla posizione iniziale del componente. Quello che vuoi fare è applicarlo alla posizione alla fine dell'ultimo gesto. Quindi in qualche modo devi salvare l'offset. AnimatedValueXY.setOffset in soccorso!

onPanResponderRelease : (e, gesture) => { 
    if(this.isDropZone(gesture)){ 
     this.setState({ 
      showDraggable : false 
     }); 
    }else{ 
     this.state.pan.setOffset({ 
      x: this.state.pan.x._offset + e.dx, 
      y: this.state.pan.y._offset + e.dy, 
     }) 
     this.state.pan.setValue({x: 0, y: 0}) 
} 

Qui sto utilizzando la variabile _offset interna perché ho trovato un modo per accedervi tramite l'API. Ovviamente puoi anche solo tenere traccia dell'offset manualmente. Non ho ancora testato questo codice, ma hai avuto l'idea.

+0

ci sono alcuni bug in questo codice, il principale è che 'setOffset' si aspetta un oggetto con x/y:' {x: numero, y: numero} '. Inoltre, come hai affermato, dovresti tenere traccia dei valori e usarli. Vedi la mia risposta. –

+0

Grazie per il suggerimento sulla firma. Ha letto male i documenti. Non penso che ci sia bisogno di un listener su AnimatedValue. Hai tutte le informazioni che ti servono al momento del rilascio. L'unica cosa è scrivere l'offset da qualche parte invece di fare affidamento su una variabile interna. –

+0

Questo codice non funziona. Porta a comportamenti strani, ad es. dopo averlo spostato una volta tornato al centro, l'app si blocca. In particolare 'e.dx' e' e.dy' sono zero e dopo ogni trascinamento 'this.state.pan.x._offset' e' this.state.pan.y._offset' sono '0'. Tuttavia, suppongo anche che ci dovrebbe essere una soluzione senza aggiungere un listener. Nel caso in cui ci siano più cerchi che si muovono liberamente questo potrebbe diventare un problema di prestazioni. – Andru

3

Un altro modo sarebbe quello di tracciare l'offset corrente e continuare ad aggiungerlo al piatto.Così dichiararlo nel costruttore currentPanValue : {x: 0, y: 0},

e modificare i onPanResponderRelease al seguente:

onPanResponderRelease   : (e, gesture) => { 
       this.state.currentPanValue.x += this.state.pan.x._value; 
       this.state.currentPanValue.y += this.state.pan.y._value; 

       this.state.pan.setOffset({x: this.state.currentPanValue.x, y: this.state.currentPanValue.y}); 
       this.state.pan.setValue({x: 0, y: 0}); 
      } 

Incase se si desidera che le coordinate finali, si dovrebbe ottenere con this.state.currentPanValue