问题
I have a parent PanResponder
with a child TouchableOpacity.
What happens is that the TouchableOpacity
doesn't respond to clicks because the PanResponder
takes the click.
I have tried to follow this guide but no success:
http://browniefed.com/blog/react-native-maintain-touchable-items-with-a-parent-panresponder/
this is my code:
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
return gestureState.dx != 0 && gestureState.dy != 0;
},
onPanResponderGrant: (evt, gestureState) => {
let isFirst = gestureState.y0 > 164 ? false : true;
this.setState({animObj: isFirst, isUsingCurtain: true});
},
onPanResponderMove: (evt, gestureState) => {
//let Y = this.state.animObj ? gestureState.moveY - this.state.currentHeaderHeight : gestureState.moveY - this.state.currentHeaderHeight ;// - this.state.currentHeaderHeight;
let Y = gestureState.moveY - this.state.currentHeaderHeight + 20
if (Y < 0) {
return false
}
this.state.animCurtain.setValue(Y);
gestureState.moveY > height / 2 ? this.setState({curtainOnMiddle: true}) : this.setState({curtainOnMiddle: false})
},
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
if (((height / 2) > gestureState.moveY)) {//slide back up1
this._CurtainAnimation(0, false);
} else {//slide to bottom
let val = height - calcSize(180);
this._CurtainAnimation(val, true);
}
},
onPanResponderTerminate: (evt, gestureState) => {
},
onPanResponderStart: (e, gestureState) => {
},
});
and this is my View :
<Animated.View
style={[styles.bottomHPHeader, TopArroOpacity ? {opacity: TopArroOpacity} : ""]} {...this._panResponder.panHandlers}>
<TouchableOpacity onPress={() => this._animateAutoCurtain()}>
{this.state.curtainOnMiddle ?
<AIIcon image={require('../../../../assets/images/homepage/close_drawer_arrow.png')}
boxSize={30}/>
: <AIIcon image={require('../../../../assets/images/homepage/open_drawer_arrow.png')}
boxSize={30}/>}
</TouchableOpacity></Animated.View>
Thank you
回答1:
The solution for my case was to modify onMoveShouldSetPanResponder
onMoveShouldSetPanResponder: (evt, gestureState) => {
//return true if user is swiping, return false if it's a single click
return !(gestureState.dx === 0 && gestureState.dy === 0)
}
回答2:
Perfect! I just needed to adjust because of the sensitivity.
onMoveShouldSetPanResponder: (evt, gestureState) => {
const { dx, dy } = gestureState
return dx > 2 || dx < -2 || dy > 2 || dy < -2
}
回答3:
I had the same exact issue. The solution was a combination of the above solutions. Had to add a condition for both the onMoveShouldSetPanResponder and onMoveShouldSetPanResponderCapture. Here is what I did.
onMoveShouldSetPanResponder: (_, gestureState) => {
const { dx, dy } = gestureState
return (dx > 2 || dx < -2 || dy > 2 || dy < -2)
},
onMoveShouldSetPanResponderCapture: (_, gestureState) => {
const { dx, dy } = gestureState
return (dx > 2 || dx < -2 || dy > 2 || dy < -2)
},
回答4:
this.panResponder = PanResponder.create({
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
});
回答5:
I came up to the similar problem but for me having a container view containing the pan view inside while having the button on absolute position & keeping it above pan view did help. It could not fit for everyone but for the cases (like mine) where button can be absolutely positioned, it works.
Here's a sample code of a component that has the pan view and button.
import React, { Component } from "react";
import {
Animated,
View,
Text,
StyleSheet,
PanResponder,
TouchableOpacity
} from "react-native";
export class ToolRuler extends Component {
constructor(props) {
super(props);
this.state = {
moveX: 0,
moveY: 0
};
}
componentWillMount() {
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
// anything
},
onPanResponderMove: (evt, gestureState) => {
this.setState({
moveX: gestureState.moveX,
moveY: gestureState.moveY
});
},
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
this.setState({
moveX: gestureState.moveX,
moveY: gestureState.moveY
});
},
onPanResponderTerminate: (evt, gestureState) => {},
onPanResponderStart: (e, gestureState) => {}
});
}
render() {
return (
<View
style={{
flex: 1,
position: "relative",
alignItems: "center",
justifyContent: "center"
}}
>
<Animated.View
{...this._panResponder.panHandlers}
style={{ flex: 1, width: "100%", backgroundColor: "#ccc" }}
>
<Text style={{ marginTop: 200, textAlign: "center" }}>
x: {this.state.moveX}, y: {this.state.moveY}
</Text>
</Animated.View>
<TouchableOpacity
style={{
position: "absolute"
}}
onPress={() => alert("I am tapped!")}
>
<Text>Click Me</Text>
</TouchableOpacity>
</View>
);
}
}
回答6:
My solution for Android. All others return false
onMoveShouldSetPanResponder: (evt, { dx, dy }) => dx !== 0 || dy !== 0,
回答7:
It seems a slightly different situation works for everyone... here is the combination of PanResponder.create
properties which worked for me (I was trying to allow taps through to child elements, but capture moves with the PanResponder:
onStartShouldSetPanResponder: ( e, state ) => false,
onStartShouldSetPanResponderCapture: ( e, state ) => false,
onMoveShouldSetPanResponder: ( e, state ) => true,
onMoveShouldSetPanResponderCapture: ( e, state ) => true,
I hope this helps someone else and it doesn't somehow come back to haunt me!
来源:https://stackoverflow.com/questions/47568850/touchableopacity-with-parent-panresponder