I'm building a Music Player and I'm focusing on the progress bar. I was able to react to swipe gestures, but I cant limit how far that gesture goes.
This is what I've done so far. I've reduced everything to the minumal:
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY()
};
}
componentWillMount() {
this._panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
// Set the initial value to the current state
let x = (this.state.pan.x._value < 0) ? 0 : this.state.pan.x._value;
this.state.pan.setOffset({ x, y: 0 });
this.state.pan.setValue({ x: 0, y: 0 });
},
onPanResponderMove: Animated.event([
null, { dx: this.state.pan.x, dy: 0 },
]),
onPanResponderRelease: (e, { vx, vy }) => {
this.state.pan.flattenOffset();
}
});
}
render() {
let { pan } = this.state;
// Calculate the x and y transform from the pan value
let [translateX, translateY] = [pan.x, pan.y];
// Calculate the transform property and set it as a value for our style which we add below to the Animated.View component
let imageStyle = { transform: [{ translateX }, { translateY }] };
return (
<View style={styles.container}>
<Animated.View style={{imageStyle}} {...this._panResponder.panHandlers} />
</View>
);
}
Here there is an image showing what the problem is.
So the idea is to stop keeping moving once the limit (left as well as right) is reached. I tried checking if _value < 0
, but it didn't work since It seems to be an offset, not a position.
Well any help will be appreciated.
This is documentation for React Native 0.60, which is no longer actively maintained. For up-to-date documentation, see the latest version ( 0.66 ). PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize basic multi-touch gestures.
PanResponder reconciles several touches into a single gesture. It makes single-touch gestures resilient to extra touches, and can be used to recognize basic multi-touch gestures. By default, PanResponder holds an InteractionManager handle to block long-running JS events from interrupting active gestures.
By default, PanResponder holds an InteractionManager handle to block long-running JS events from interrupting active 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:
Try the PanResponder example in RNTester. The config object provides enhanced versions of all of the responder callbacks that provide not only the PressEvent, but also the PanResponder gesture state, by replacing the word Responder with PanResponder in each of the typical onResponder* callbacks. For example, the config object would look like:
Instead of letting your animation die at your borders, you could interpolate your Animated.Value with y=x, but with clamping it to your width.
return (
<View style={styles.container}>
<Animated.View
style={{
transform: [{
translateX: this.state.pan.x.interpolate({
inputRange: [0, trackWidth ],
outputRange: [0, trackWidth ],
extrapolate: 'clamp'
})
}],
}}
{...this._panResponder.panHandlers}
/>
</View>
);
Here's a more in-depth example: https://github.com/olapiv/expo-audio-player/blob/master/src/AudioSlider.js
onPanResponderMove: (e, gestureState)=> {
this.state.pan.x._value > 0 ? null : Animated.event([
null,
{dx: this.state.pan.x, dy: this.state.pan.y},
])(e, gestureState)
},
I was trying to do something similar; I wanted to have it so that you can pull the page part way and then release and it goes back to where it was.
My solution was this:
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (e, { dx }) => {
// This will make it so the gesture is ignored if it's only short (like a tap).
// You could also use moveX to restrict the gesture to the sides of the screen.
// Something like: moveX <= 50 || moveX >= screenWidth - 50
// (See https://facebook.github.io/react-native/docs/panresponder)
return Math.abs(dx) > 20;
},
onPanResponderMove: (e, gestureState) => (
// Here, 30 is the limit it stops at. This works in both directions
Math.abs(gestureState.dx) > 30
? null
: Animated.event([null, { dx: this.animatedVal }])(e, gestureState)
),
onPanResponderRelease: (e, { vx, dx }) => {
// Here, abs(vx) is the current speed (not velocity) of the gesture,
// and abs(dx) is the distance traveled (not displacement)
if (Math.abs(vx) >= 0.5 || Math.abs(dx) >= 30) {
doSomeAction();
}
Animated.spring(this.animatedVal, {
toValue: 0,
bounciness: 10,
}).start();
},
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With