react-native: [PanResponder] onPanResponderMove locationX/locationY values incorrect
Is this a bug report?
yes
Have you read the Bugs section of the How to Contribute guide?
yes
Environment
react-native -v
: 0.43.4node -v
: v6.9.1npm -v
: 3.10.8yarn --version
: 0.18.1
Then, specify:
-
Target Platform: iOS
-
Development Operating System: macOS
-
Build tools: Xcode
Steps to Reproduce
(Write your steps here:)
- use panResponder
- console.log locationX and locationY of view when I move it in onPanResponderMove
Expected Behavior
the locationX change with the view move
Actual Behavior
locationX do change when view move, but the value is not currect, just like:
locationX : 38.5 locationY : 53.5 locationX : 152.5 locationY : 278.5 locationX : 29.5 locationY : 45 locationX : 138 locationY : 264.5
Reproducible Demo
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`locationX : ${evt.nativeEvent.locationX} locationY : ${evt.nativeEvent.locationY}`);
this.setState({
marginLeft: evt.nativeEvent.locationX,
marginTop: evt.nativeEvent.locationY,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
redView: {
width: 100,
height: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 20 (5 by maintainers)
Commits related to this issue
- React sync Summary: This sync includes the following changes: - **[1b2159acc](https://github.com/facebook/react/commit/1b2159acc )**: [React Native] measure calls will now call FabricUIManager (#1532... — committed to facebook/react-native by TheSavior 5 years ago
- React sync Summary: This sync includes the following changes: - **[1b2159acc](https://github.com/facebook/react/commit/1b2159acc )**: [React Native] measure calls will now call FabricUIManager (#1532... — committed to facebook/react-native by TheSavior 5 years ago
- React sync for revisions 8e25ed2...ec6691a Summary: This sync includes the following changes: - **[ec6691a68](https://github.com/facebook/react/commit/ec6691a68 )**: Event API: remove isTargetDirectl... — committed to facebook/react-native by mdvacca 5 years ago
- React sync for revisions 8e25ed2...ec6691a Summary: This sync includes the following changes: - **[ec6691a68](https://github.com/facebook/react/commit/ec6691a68 )**: Event API: remove isTargetDirectl... — committed to calebmer/react-native by mdvacca 5 years ago
Regarding the issue where two clicks within a second will yield two
onPanResponderGrant
events, the second of which has wildly incorrectlocationX
/locationY
values: this issue is still extant in 0.51. I should note that this seems to be distinct from theonPanResponderMove
issue withlocationX
/locationY
, but I assume they are related. I haven’t checked that one on 0.51, but I assume it’s still going on as well.Overall, the issue is that the relative positions reported by
PanResponder
are impossibly to rely on. This forces developers to rely on absolute positions reported by layout calls, but sinceonLayout
does not report absolute positions, messymeasure()
calls are necessary.I do not think we should close this issue, as this problem prevents the use of
PanResponder
for correct relative positioning information. In my opinion, this is the kind of “wtf?” experience that turns off a lot of newcomers from React Native.I don’t know if this has been fixed in later versions of react-native. However my rather simple workaround is based on the fact that locationX seems to be accurate in the onResponderGrant event so in the onResponderGrant handler I just do:
this.locationPageOffset = evt.nativeEvent.pageX - evt.nativeEvent.locationX;
then in the onResponderMove handler I can derive locationX from pageX like this.
const locationX = evt.nativeEvent.pageX - this.locationPageOffset
The first time I went down the onLayout handling route but found this simpler and more independent.
I am seeing the issue that your PR addressed as well, which is that on Android,
onPanResponderMove
doesn’t update the values oflocationX
/locationY
.However, there is another distinct issue, that I can repro on both iOS and Android. If you press a location twice in short succession, the second press will register incorrect (and in my case, far smaller) values of
locationX
andlocationY
.