Draggable React Native view

You can simply implement a draggable view in react native using default PanResponder and Animated libraries.

What is PanResponder?

PanResponder library is responsiple for gesture events. It basically handles the event when users touch the screen and move their fingers simultaneously (dragging is an example of PanResponder usage).

Official documentation: https://facebook.github.io/react-native/docs/panresponder#docsNav

Main functions of PanResponder

  • onStartShouldSetPanResponder: to set if this instance of PanResponder should start or not.
  • onPanResponderMove: this function gets triggered when users move thier fingers on the screen.
  • onPanResponderRelease: this function gets triggered when users release their fingers from the screen.

What is Animated?

You need Animated library to animate different features of react native elements. In our example, you are going to animate the X and Y coordinates by using the VaueXY function.

Official documentatin: https://facebook.github.io/react-native/docs/animated#docsNav

Implementing the draggable view

The draggable element

You must use the Animated.View element type for draggable element to be able to animate the movement of it.

Connecting PanResponder to draggable element

To connect PanResponder to any element you basically need to attach panHandlers object of PanResponder to the element. Example:

<Animated.View 
    style={[this.getBallStyle() ,styles.circle]}
    {...this.state.panResponder.panHandlers}>
  
</Animated.View>

Animating the movement of the draggable element

The animation occurs on two steps.

  1. Initiating position by calling new Animated.ValueXY()
  2. Animating the movement by calling setValue({x, y})

Complete code

import React, {Component } from 'react';
import { 
  StyleSheet, 
  Animated,
  PanResponder, 
  View 
} from 'react-native';

class App extends Component {

  x = 0 ;
  y = 0 ;
  constructor(props)
  {
      super(props);

      const position = new Animated.ValueXY();
      const panResponder = PanResponder.create({
          onStartShouldSetPanResponder : () => true,
          onPanResponderMove : (event , gesture) => {
            position.setValue({x : this.x + gesture.dx, y : this.y + gesture.dy});
          },
          onPanResponderRelease : (event , gesture) => {
            this.x += gesture.dx;
            this.y += gesture.dy;
          }
      });
      this.state = {panResponder, position};
  }

  getBallStyle()
  {
      const { position } = this.state;
      
      return position.getLayout();
  }

  render()
  {
    return (
      <View style={styles.container}>
        <Animated.View 
        style={[this.getBallStyle() ,styles.circle]}
        {...this.state.panResponder.panHandlers}>
  
        </Animated.View>
        
      </View>
    );
  }  
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  circle: {
    borderRadius: 25,
    borderColor: 'red',
    borderWidth: 25,
    width: 50
  }
});

export default App;

Leave a Reply

Your email address will not be published. Required fields are marked *