我尝试使用PanResponder和Animated在native native中实现抽屉。
我有以下代码:
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;
正如你在这里看到的那样,我试图移动抽屉视图,当用户按下左角500ms并且抽屉视图移动10像素并且用户可以拖动它时。
这可以在iOS上正常工作,你可以在这里看到
CustomDrawer
但同样在Android中无效。我尝试过调试,但Android中没有调用 onPanResponderGrant 。
答案 0 :(得分:0)
通过使用onPanResponderEnd
而不是onPanResponderRelease
使它正常工作。
此外,如果您仍然想使用onPanResponderRelease
,则应通过以下方式允许终止请求:
onPanResponderTerminationRequest: () => true