Reputation: 5755
Below is the snippet for creating an instance of the panResponder
:
constructor( props ) {
super( props );
this.position = new Animated.ValueXY();
this.panResponder = PanResponder.create( {
onStartShouldSetPanResponder: ( ) => true,
onPanResponderMove: ( event, gesture ) => {
this.position.setValue( { x: 0, y: gesture.dy } );
},
onPanResponderRelease: ( event, gesture ) => {
if ( gesture.dy > SWIPE_THRESHOLD ) {
this.forceSwipe( 'up' );
} else if ( gesture.dy < -SWIPE_THRESHOLD ) {
this.forceSwipe( 'down' );
} else {
this.resetPosition();
}
},
onMoveShouldSetPanResponderCapture: ( evt, gestureState ) =>
gestureState.dx !== 0 && gestureState.dy !== 0,
} );
}
getCardStyle() {
return {
...this.position.getLayout(),
};
}
Below is the code snippet of my Component:
<Animated.View
key={ item.id }
style={ [ this.getCardStyle(), styles.cardStyle ] }
{ ...this.panResponder.panHandlers }
>
<Card
shouldPanRespond={ this.shouldPanRespond }
item={ item }
/>
</Animated.View>
Code snippet for card component:
<TouchableOpacity
activeOpacity={ 1 }
style={ cardStyle }
onPress={ this.onPress }
>
<ScrollView contentContainerStyle={ cardStyle }>
<Image
resizeMode="cover"
style={ imageStyle }
source={ { uri: img_url } }
/>
<View style={ titleWrapStyle }>
<Text style={ textStyle }>{ title }</Text>
</View>
</ScrollView>
</TouchableOpacity>
I am building cards that are absolutely positioned one behind another. These cards can then be swiped up or down using the panResponder
. But, on tapping the screen I am supposed to show a detail page on the same screen.
Now, I can detect the tap, but whenever the user taps/clicks, I want to disable the panResponder
so that the card cannot be swiped and the user can scroll through the content. Once, the user scrolls to the end, I want to re-enable swiping i.e I want to enable panning.
I know that onStartShouldSetResponder: () => false
disables panResponder
but how do we disable it after an instance is created. I couldn't find much about it else where.
Upvotes: 6
Views: 9821
Reputation: 23
If you want a really simple brute force solution use the pointerEvents
prop on the animated view.
pointerEvents={stopPan ? 'none' : 'auto'}
This will stop all touch events on the view and all below it firing while stopPan
is true.
Upvotes: 2
Reputation: 11
I think I found a way to disable PanResponder temporarily using onStartShouldSetResponder. The goal is to toggle between true and false, even though it doesn't seem to respond to changes in state values. If you're using functional components, the hook useRef
seems to do the trick.
const [panResponderEnabled, _setPanResponderEnabled] = useState(true)
const panResponderEnabledRef = useRef(panResponderEnabled)
const setPanResponderEnabled = data => {
panResponderEnabledRef.current = data
_setPanResponderEnabled(data)
}
Then when you create your PanResponder:
onStartShouldSetPanResponder: () => panResponderEnabledRef.current,
Upvotes: 1
Reputation: 311
For someone who will be looking how to temporarily disable PanResponder, below is my solution.
Like @RaHuL - House Javascript noticed, the other answer doesn't really solve the problem because setting onStartShouldSetResponder
to value corresponding to some state value which might change from true to false won't affect PanResponder (at least it seems so) if it was created with true
.
I solved similar problem by changing onPanResponderMove
function. I have a value inside state: panResponderEnabled
and my function looks like this:
onPanResponderMove: ( event, gesture ) => {
if(this.state.panResponderEnabled){
this.position.setValue( { x: 0, y: gesture.dy } );
}
}
When I don't want to read changes from PanRespoder I just set panResponderEnabled
to false.
Upvotes: 5
Reputation: 8678
Instead of the arrow function for onStartShouldSetResponder
you can use class function and use state to return true/false. Something like this
constructor( props ) {
super( props );
this.state = {
panResponderEnabled: true
}
this.position = new Animated.ValueXY();
this.panResponder = PanResponder.create( {
onStartShouldSetPanResponder: ( ) => true,
onPanResponderMove: ( event, gesture ) => {
this.position.setValue( { x: 0, y: gesture.dy } );
},
onPanResponderRelease: ( event, gesture ) => {
if ( gesture.dy > SWIPE_THRESHOLD ) {
this.forceSwipe( 'up' );
} else if ( gesture.dy < -SWIPE_THRESHOLD ) {
this.forceSwipe( 'down' );
} else {
this.resetPosition();
}
},
onMoveShouldSetPanResponderCapture: ( evt, gestureState ) =>
gestureState.dx !== 0 && gestureState.dy !== 0,
} );
}
handlePanResponderStart = () => {
return this.state.panResponderEnabled;
}
onCardPress = () => {
this.setState({
panResponderEnabled: false
});
}
getCardStyle() {
return {
...this.position.getLayout(),
};
}
Upvotes: -1