I’m working on a project where I’m trying to create a draggable object that when dragged in between two markers and the animation is released/ended will spring/move to the closest marker. The problem that I’m having is that the object keeps springing to the first or second marker even if I’ve only been touching and grabbing the object from the third marker. I’ve tried getting this to work a number of ways. I tried playing with the tension, bounciness, friction. etc. Additionally, I’ve tried putting the animated spring in the onPanResponderRelease
, but it seems to work better in the onPanResponderEnd. Does anyone know how to fix this? I would really appreciate any help or advice. Thank you!
import React, { useState, useEffect, useRef,} from 'react';
import { View, Modal, StyleSheet, FlatList, Alert, TouchableOpacity } from 'react-native';
import {
Text,
TextInput,
Pressable,
ActivityIndicator,
} from 'react-native';
import {Animated, PanResponder } from 'react-native';
export default function App(){
let length = 200;
let numOfMarkers = 4;
let value = [0,3]
const pan = useRef(new Animated.ValueXY()).current;
const panResponder = React.useMemo(() => PanResponder.create({
onMoveShouldSetPanResponder: () => true,
onStartShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
if (Number.parseInt(JSON.stringify(pan.x)) < 0) {
pan.setOffset({
x: 0,
y: 0
})
}
else if (Number.parseInt(JSON.stringify(pan.x)) < length) {
pan.setOffset({
x: pan.x._value,
y: 0
})
}
else {
pan.setOffset({
x: length,
y: 0
})
}
},
onPanResponderMove:(evt, gestureState) => {
Animated.event([null, { dx: pan.x}],{ useNativeDriver: false })(evt, gestureState)
},
onPanResponderEnd: (evt, gestureState) => {
let moveX = Number.parseInt(JSON.stringify(pan.x)) <= 0 ? 0 : (Number.parseInt(JSON.stringify(pan.x)) <= length ? Number.parseInt(JSON.stringify(pan.x)) : length)
let lengthVal = length/(numOfMarkers -1)
for ( i=0; numOfMarkers > i; i++) {
if ((lengthVal * i) + lengthVal/2 > moveX && (lengthVal * i) - lengthVal/2 < moveX ) {
let valueRel = (lengthVal-6)*i
let springVal = Number.parseInt(JSON.stringify(pan.x));
Animated.spring(pan.x, {
toValue: valueRel,
friction: 1,
tension: 3,
overshootClamping: true, //not working
useNativeDriver: true,
duration:1,
}).start()
break
}
}
},
onPanResponderRelease: (evt, gestureState) => {
pan.flattenOffset()
},
}), [pan]);
const Dots = ({numOfMarkers}) => {
return (
<View style={{flexDirection:'row', justifyContent:'space-between', width:length, alignSelf:'center'}}>
{new Array(numOfMarkers).fill(0).map((e, i) => {
return (
<View style={{
width:20,
height:20,
borderRadius:20,
backgroundColor:'blue',
}}>
</View>
)
})}
</View>
)
}
return (
<View style={{marginTop:10, height:30, width:length+40, alignSelf:'center', justifyContent:'center',}}>
<View
style={{
justifyContent:'center',
alignSelf:'center',
width:length,
backgroundColor:'black',
height:10,
}}
>
<Animated.View
style={{
width:20,
height:20,
borderRadius:20,
backgroundColor:'red',
justifyContent:'center',
position:'absolute',
zIndex:1,
transform:[{translateX: pan.x.interpolate({
inputRange: [0, length-20],
outputRange: [0, length-20],
extrapolate: 'clamp'})}]
}}
{...panResponder.panHandlers}
/>
<Dots numOfMarkers={numOfMarkers}/>
</View>
</View>
);
}