Skip to main content
PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize simple multi-touch gestures. It provides a predictable wrapper of the responder handlers provided by the gesture responder system. For each handler, it provides a new gestureState object alongside the native event object.

Methods

create()

static create(config: PanResponderCallbacks)
Creates a new PanResponder instance with the provided configuration.
config
object
required
Configuration object containing responder callbacks
onStartShouldSetPanResponder
function
Called to determine whether to become the responder on the start of a touchSignature: (event, gestureState) => boolean
onStartShouldSetPanResponderCapture
function
Called during the capture phase to determine whether to become the responderSignature: (event, gestureState) => boolean
onMoveShouldSetPanResponder
function
Called when a touch moves to determine whether to become the responderSignature: (event, gestureState) => boolean
onMoveShouldSetPanResponderCapture
function
Called during the capture phase when a touch movesSignature: (event, gestureState) => boolean
onPanResponderGrant
function
Called when the view becomes the responder. Show visual feedback.Signature: (event, gestureState) => void
onPanResponderReject
function
Called when another component has become the responderSignature: (event, gestureState) => void
onPanResponderStart
function
Called when a touch startsSignature: (event, gestureState) => void
onPanResponderMove
function
Called when the touch movesSignature: (event, gestureState) => void
onPanResponderEnd
function
Called when a touch endsSignature: (event, gestureState) => void
onPanResponderRelease
function
Called when the user has released all touches. This typically means a gesture has succeeded.Signature: (event, gestureState) => void
onPanResponderTerminate
function
Called when another component has become the responder, so this gesture should be cancelledSignature: (event, gestureState) => void
onPanResponderTerminationRequest
function
Called to determine whether this responder should be terminatedSignature: (event, gestureState) => boolean
onShouldBlockNativeResponder
function
Returns whether this component should block native components from becoming the JS responder. Currently only supported on Android.Signature: (event, gestureState) => boolean
Returns: An object containing:
  • panHandlers - Props to spread on the View component
  • getInteractionHandle() - Returns interaction handle (deprecated)

GestureState Object

The gestureState object passed to handlers has the following properties:
stateID
number
ID of the gestureState - persisted as long as there is at least one touch on screen
moveX
number
The latest screen coordinates of the recently-moved touch
moveY
number
The latest screen coordinates of the recently-moved touch
x0
number
The screen coordinates of the responder grant
y0
number
The screen coordinates of the responder grant
dx
number
Accumulated distance of the gesture since the touch started
dy
number
Accumulated distance of the gesture since the touch started
vx
number
Current velocity of the gesture
vy
number
Current velocity of the gesture
numberActiveTouches
number
Number of touches currently on screen

Native Event Properties

The native event object contains:
  • nativeEvent.changedTouches - Array of all touch events that have changed since the last event
  • nativeEvent.identifier - The ID of the touch
  • nativeEvent.locationX - The X position of the touch, relative to the element
  • nativeEvent.locationY - The Y position of the touch, relative to the element
  • nativeEvent.pageX - The X position of the touch, relative to the root element
  • nativeEvent.pageY - The Y position of the touch, relative to the root element
  • nativeEvent.target - The node id of the element receiving the touch event
  • nativeEvent.timestamp - A time identifier for the touch, useful for velocity calculation
  • nativeEvent.touches - Array of all current touches on the screen

Example

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

function DraggableBox() {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderGrant: () => {
        pan.setOffset({
          x: pan.x._value,
          y: pan.y._value
        });
      },
      onPanResponderMove: Animated.event(
        [
          null,
          {dx: pan.x, dy: pan.y}
        ],
        {useNativeDriver: false}
      ),
      onPanResponderRelease: () => {
        pan.flattenOffset();
      }
    })
  ).current;

  return (
    <View style={styles.container}>
      <Animated.View
        style={{
          transform: [{translateX: pan.x}, {translateY: pan.y}]
        }}
        {...panResponder.panHandlers}>
        <View style={styles.box} />
      </Animated.View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    height: 150,
    width: 150,
    backgroundColor: 'blue',
    borderRadius: 5,
  },
});

export default DraggableBox;

Multi-Touch Example

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

class MultiTouchExample extends Component {
  constructor(props) {
    super(props);
    this.state = {
      touches: 0
    };

    this._panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderGrant: (evt, gestureState) => {
        this.setState({touches: gestureState.numberActiveTouches});
      },
      onPanResponderMove: (evt, gestureState) => {
        this.setState({touches: gestureState.numberActiveTouches});
      },
      onPanResponderRelease: () => {
        this.setState({touches: 0});
      },
    });
  }

  render() {
    return (
      <View {...this._panResponder.panHandlers} style={{flex: 1}}>
        <Text>Active touches: {this.state.touches}</Text>
      </View>
    );
  }
}

export default MultiTouchExample;

Build docs developers (and LLMs) love