TouchableOpacity with parent PanResponder

梦想的初衷 提交于 2020-04-10 07:09:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!