I'm trying to implement drawer in react native using PanResponder and Animated.
I have the following code:
CustomDrawer.js
import React, { Component } from 'react';
import {
View,
Text,
TouchableHighlight,
Modal,
TouchableWithoutFeedback,
Animated,
Dimensions,
TouchableOpacity,
PanResponder
}
from 'react-native';
import { setTimeout } from 'core-js/library/web/timers';
const SCREEN_WIDTH = Dimensions.get('window').width;
const SCREEN_HEIGHT = Dimensions.get('window').height;
const DRAWER_WIDTH = 300;
const SWIPE_THERSHOLD = DRAWER_WIDTH * 0.2;
class CustomDrawer extends Component {
visible = false;
starting = false;
state = {
drawerVisible: false,
}
constructor(props){
super(props);
const { drawerVisible } = this.state;
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderMove: (event, gesture) => {
if(this.visible){
if(gesture.dx<0){
this.position.setValue({ x: gesture.dx, y: 0});
}
else if(gesture.dx<DRAWER_WIDTH){
this.position.setValue({ x: -DRAWER_WIDTH + gesture.dx, y: 0});
}
}
},
onPanResponderRelease: (event, gesture) => {
if(this.visible) {
if(gesture.dx> 10){
this.starting = false;
}
if(gesture.dx>0){
if(gesture.dx>=SWIPE_THERSHOLD){
this.forceDrawer('right');
}
else{
this.resetAnim();
}
}
else if(gesture.dx!=0) {
if(gesture.dx < - SWIPE_THERSHOLD){
this.setState({ drawerVisible: false});
this.forceDrawer('left');
}
else {
this.renderAnim();
}
}
}
if(this.starting){
this.resetAnim();
}
},
onPanResponderGrant: (event, gesture) => {
console.log(gesture)
setTimeout(()=> {
if(gesture.x0<10 && !gesture.x0==0){
console.log(gesture.x0);
this.setState({ drawerVisible: true})
this.visible=true;
this.starting = true;
this.position.setValue({ x: 10- DRAWER_WIDTH, y: 0})
}
}, 500)
return true;
},
});
this.state = { drawerVisible: false, panResponder }
}
forceDrawer(direction) {
const x = direction === 'right' ? 0 : -DRAWER_WIDTH;
Animated.timing(this.position,{
toValue: {x: x, y: 0},
duration: 400
}).start();
}
componentWillMount() {
this.position = new Animated.ValueXY({x: -SCREEN_WIDTH, y: 0});
}
renderAnim(){
Animated.timing(this.position, {
toValue: { x: 0, y: 0},
duration: 400
}).start();
}
resetAnim() {
this.starting = false;
this.setState({ drawerVisible: false});
this.visible = false;
Animated.timing(this.position, {
toValue: { x: -SCREEN_WIDTH, y: 0},
duration: 250
}).start();
}
renderBackground() {
if(this.state.drawerVisible) {
return(
<TouchableOpacity style={styles.backgroundDrawer}
onPress={ () => {
this.resetAnim();
this.setState({drawerVisible: false});
}}>
</TouchableOpacity>
)
}
}
render() {
return(
<View style={{flex: 1}}
{...this.state.panResponder.panHandlers}>
<View style={styles.viewStyle}>
<TouchableOpacity onPress={()=> {
this.renderAnim();
this.setState({ drawerVisible: true})
this.visible=true
}}>
<Text>Open Drawer</Text>
</TouchableOpacity>
</View>
{this.renderBackground()}
<Animated.View style={[this.position.getLayout(),styles.drawerStyle]}
>
<Text>Contents</Text>
</Animated.View>
</View>
)
}
}
const styles = {
viewStyle: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden'
},
backgroundDrawer: {
height: SCREEN_HEIGHT,
width: SCREEN_WIDTH,
backgroundColor: 'rgba(0,0,0,0.2)',
position: 'absolute'
},
drawerStyle: {
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
width: DRAWER_WIDTH,
height: SCREEN_HEIGHT,
position: 'absolute',
elevation: 6,
overflow: 'hidden'
},
}
export default CustomDrawer;
As you can see here, i'm trying to move the drawer view, when the user presses on left corner for 500ms and the drawer view moves by 10pixels and user can drag it.
This works fine on iOS as you can see here
CustomDrawer
But the same is not working in Android. I tried debugging and onPanResponderGrant is not called in Android.