在Android中没有调用React Native onPanResponderGrant,但在iOS中它可以正常工作

时间:2017-11-16 05:41:35

标签: android react-native

我尝试使用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

image

但同样在Android中无效。我尝试过调试,但Android中没有调用 onPanResponderGrant

1 个答案:

答案 0 :(得分:0)

通过使用onPanResponderEnd而不是onPanResponderRelease使它正常工作。

此外,如果您仍然想使用onPanResponderRelease,则应通过以下方式允许终止请求:

onPanResponderTerminationRequest: () => true