import React, { Component } from 'react'; import { StyleSheet, View, PanResponder, I18nManager, GestureResponderEvent, PanResponderGestureState, Alert, GestureResponderHandlers, } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { DraggableBox } from '../draggable'; import { LoremIpsum } from '../../common'; const CIRCLE_SIZE = 80; type CircleStyles = { backgroundColor?: string; left?: number; top?: number; }; // A clone of: https://github.com/facebook/react-native/blob/master/packages/rn-tester/js/examples/PanResponder/PanResponderExample.js class PanResponderExample extends Component { private panResponder: { panHandlers?: GestureResponderHandlers } = {}; private previousLeft = 0; private previousTop = 0; private circleStyles: { style: CircleStyles } = { style: { left: 0, top: 0, backgroundColor: '#000' }, }; private circle: React.ElementRef | null = null; UNSAFE_componentWillMount() { this.panResponder = PanResponder.create({ onStartShouldSetPanResponder: this.handleStartShouldSetPanResponder, onMoveShouldSetPanResponder: this.handleMoveShouldSetPanResponder, onPanResponderGrant: this.handlePanResponderGrant, onPanResponderMove: this.handlePanResponderMove, onPanResponderRelease: this.handlePanResponderEnd, onPanResponderTerminate: this.handlePanResponderEnd, }); this.previousLeft = 20; this.previousTop = 84; this.circleStyles = { style: { left: this.previousLeft, top: this.previousTop, backgroundColor: 'green', }, }; } componentDidMount() { this.updateNativeStyles(); } render() { return ( { this.circle = circle; }} style={styles.circle} {...this.panResponder.panHandlers} /> ); } private highlight = () => { this.circleStyles.style.backgroundColor = 'blue'; this.updateNativeStyles(); }; private unHighlight = () => { this.circleStyles.style.backgroundColor = 'green'; this.updateNativeStyles(); }; private updateNativeStyles = () => { this.circle?.setNativeProps(this.circleStyles); }; private handleStartShouldSetPanResponder = ( _e: GestureResponderEvent, _gestureState: PanResponderGestureState ) => { // Should we become active when the user presses down on the circle? return true; }; private handleMoveShouldSetPanResponder = ( _e: GestureResponderEvent, _gestureState: PanResponderGestureState ) => { // Should we become active when the user moves a touch over the circle? return true; }; private handlePanResponderGrant = ( _e: GestureResponderEvent, _gestureState: PanResponderGestureState ) => { this.highlight(); }; private handlePanResponderMove = ( _e: GestureResponderEvent, gestureState: PanResponderGestureState ) => { this.circleStyles.style.left = this.previousLeft + gestureState.dx * (I18nManager.isRTL ? -1 : 1); this.circleStyles.style.top = this.previousTop + gestureState.dy; this.updateNativeStyles(); }; private handlePanResponderEnd = ( _e: GestureResponderEvent, gestureState: PanResponderGestureState ) => { this.unHighlight(); this.previousLeft += gestureState.dx * (I18nManager.isRTL ? -1 : 1); this.previousTop += gestureState.dy; }; } export default class Example extends Component { onClick = () => { Alert.alert("I'm so touched"); }; render() { return ( ); } } const styles = StyleSheet.create({ scrollView: { flex: 1, backgroundColor: '#F5FCFF', }, circle: { width: CIRCLE_SIZE, height: CIRCLE_SIZE, borderRadius: CIRCLE_SIZE / 2, zIndex: 100, }, });