Reputation: 2373
I am trying to figure out how I can capture all click events to determine if they were clicked outside of my SearchBar drop down menu. If so then the drop down menu will close. I have a way of detecting all click events (TouchableWithoutFeedback) but I am not able to figure out a way to compare or determine if it was outside of my component or not. Anyone know how to do this in React Native??
class Products extends Component {
constructor(props) {
super(props);
this.hideSearchBar = this.hideSearchBar.bind(this);
}
hideSearchBar(e) {
console.log('e: ', e.nativeEvent.target)
// Determine if the click event was outside of the SearchBar component
}
render() {
const {isLoading, products} = this.props.products;
return (
<TouchableWithoutFeedback onPress={(e) => this.hideSearchBar(e)} style={{zIndex: 0}}>
<View style={styles.wrapper}>
<Header/>
<View style={styles.bodyWrapper}>
<ScrollView style={styles.scrollView}>
<ProductsContainer data={{productsList: { results: products }}}/>
</ScrollView>
<SearchBar ref={node => this.node = node} style={styles.searchBar}/>
</View>
<Footer/>
</View>
</TouchableWithoutFeedback>
);
}
}
Upvotes: 7
Views: 4884
Reputation: 22189
You can check the clicks based on the PanResponder.
PanResponder
contains the methods as mentioned here.
But you only need
onMoveShouldSetPanResponderCapture
: To set the capture of movement of the interaction.onPanResponderMove
: To capture the events on moveonPanResponderTerminationRequest
: Terminate responder if other resource requires access to it.Here's the simple example
Note: You need to set the PanResponder Handler
on the Parent View to access the touch events in the whole screen.
const touchThreshold = 20;
state = {
outsideTarget: null,
}
componentWillMount () {
this._panResponder = PanResponder.create({ //...Create the Responder
// Ask to be the responder:
// Ask to be the responder:
onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
const {dx, dy} = gestureState;
return (Math.abs(dx) > touchThreshold) || (Math.abs(dy) > touchThreshold);
},
onPanResponderMove: (evt, gestureState) => {
console.log('Responder' + evt.nativeEvent.target)
this.setState({outsideTarget: true})
// The most recent move distance is gestureState.move{X,Y}
// The accumulated gesture distance since becoming responder is
// gestureState.d{x,y}
},
onPanResponderTerminationRequest: (evt, gestureState) => true,
});
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.state.outsideTarget) {
Alert.alert('Success', 'Component Clicked OutSide')
} else if(!this.state.outsideTarget) {
Alert.alert('Success', 'Component Clicked Inside')
}
}
hideSearchBar(e) {
// Determine if the click event was outside of the SearchBar component
this.setState({outsideTarget: false})
}
render() {
return (
<View style={{flex: 1}} {...this._panResponder.panHandlers}> //...Set the responder to the parent view
<TouchableOpacity onPressIn={(e) => this.hideSearchBar(e)} style={{height: 100, width: 100, backgroundColor: 'red'}} />
</View>
);
}
If the responder's native event target matches the touchable's native event target then it is inside, else outside
Upvotes: 3