react-nativeexpo

React Native Panresponder issue after retouching and moving the image return back to initial position


I have one draggable car image if i dragging the car first time it works fine after second time re dragging the car image return back to the initial position. I want to drag an image smooth and draggable with finger touch. please help me

import React, { Component } from 'react'; import { StyleSheet, View, Text, PanResponder, Animated, Easing, Dimensions, Image, Button } from 'react-native'; import { ToastAndroid } from 'react-native';

export default class Viewport extends Component {
  constructor(props) {
    super(props);

    this.state = {
      disableCar: false,
      dropZoneCar: null,
      panCar: new Animated.ValueXY(),
    };
    this.carFunction();
  }

  carFunction = () => {
    this.panResponderCar = PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([null, {
        dx: this.state.panCar.x,
        dy: this.state.panCar.y
      }]),
      onPanResponderGrant: (evt, gestureState) => {
        console.log(evt)
      },

      onPanResponderRelease: (e, gesture) => {
        // console.log(e)

        if (this.isDropZoneCar(gesture)) {
          ToastAndroid.show('Correct', ToastAndroid.SHORT);
        } else {
          ToastAndroid.show('Wrong', ToastAndroid.SHORT);
        }
      }
    });
  }

  isDropZoneCar(gesture) {
    var dz = this.state.dropZoneCar;
    return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
  }

  setDropZoneCar(event) {
    this.setState({
      dropZoneCar: event.nativeEvent.layout
    });
  }
  setDropZoneBike(event) {
    this.setState({
      dropZoneBike: event.nativeEvent.layout
    });
  }
  render() {

    return (
      <View style={styles.mainContainer}>
        <View style={{ flexDirection: 'row', }}>
          <View style={{ flex: 1 }}>
            <View
              onLayout={this.setDropZoneCar.bind(this)}
              style={[styles.dropZone, { backgroundColor: this.state.disableCar ? 'green' : '#2c3e50' }]}>
              <Text style={styles.text}>Drop a Car</Text>
            </View>
            <View
              onLayout={this.setDropZoneBike.bind(this)}
              style={[styles.dropZone, { backgroundColor: this.state.disableCar ? 'green' : '#2c3e50' }]}>
              <Text style={styles.text}>Drop a Bike</Text>
            </View>
          </View>
          <View style={{ flex: 1 }}>
            {this.draggableCar()}
          </View>
        </View>
      </View>
    );
  }

  draggableCar() {
    return (
      <View style={styles.draggableContainer} >
        <Animated.View
          {...this.panResponderCar.panHandlers}
          style={[this.state.panCar.getLayout()]}>
          <Image
            style={{ position: "absolute", width: 200, height: 100, right: 10, top: 300, }}
            source={require('./assets/carr.png')}
          />
        </Animated.View>
      </View>
    );
  }
}

let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
let styles = StyleSheet.create({
  mainContainer: {
    flex: 1
  },
  dropZone: {
    height: 100,
    backgroundColor: '#2c3e50',
    marginTop: 100
  },
  text: {
    marginTop: 25,
    marginLeft: 5,
    marginRight: 5,
    textAlign: 'center',
    color: '#fff'
  },
  draggableContainer: {
    position: 'absolute',
    top: Window.height / 2 - CIRCLE_RADIUS,
    left: Window.width / 2 - CIRCLE_RADIUS,
  },
});

Solution

  • You are listening to the delta of the finger movement dx and dy, so whenever you touch again, your pan values drop to 0's. You should set an offset on your pan values every time you touch to fix this. Add this piece of code:

    onPanResponderGrant: (e, gestureState) => {
      this.state.panCar.setOffset({x: this.state.panCar.x._value, y: this.state.panCar.y._value});
      this.state.panCar.setValue({x: 0, y: 0});
    }
    

    This will set the offset for your pan to current position, so it doesn't jump back after consequent touches. Hope this helps.