简体   繁体   English

React Native:如何暂时禁用 PanResponder?

[英]React Native: How to disable PanResponder temporarily?

Below is the snippet for creating an instance of the panResponder :下面是创建panResponder实例的代码片段:

  constructor( props ) {
    super( props );

    this.position = new Animated.ValueXY();

    this.panResponder = PanResponder.create( {
      onStartShouldSetPanResponder: ( ) => true,
      onPanResponderMove: ( event, gesture ) => {
        this.position.setValue( { x: 0, y: gesture.dy } );
      },
      onPanResponderRelease: ( event, gesture ) => {
        if ( gesture.dy > SWIPE_THRESHOLD ) {
          this.forceSwipe( 'up' );
        } else if ( gesture.dy < -SWIPE_THRESHOLD ) {
          this.forceSwipe( 'down' );
        } else {
          this.resetPosition();
        }
      },
      onMoveShouldSetPanResponderCapture: ( evt, gestureState ) =>
      gestureState.dx !== 0 && gestureState.dy !== 0,
    } );
  }

  getCardStyle() {
    return {
      ...this.position.getLayout(),
    };
  }

Below is the code snippet of my Component:下面是我的组件的代码片段:

<Animated.View
   key={ item.id }
   style={ [ this.getCardStyle(), styles.cardStyle ] }
   { ...this.panResponder.panHandlers }
>
  <Card
    shouldPanRespond={ this.shouldPanRespond }
     item={ item }
  />
</Animated.View>

Code snippet for card component:卡片组件的代码片段:

  <TouchableOpacity
    activeOpacity={ 1 }
    style={ cardStyle }
    onPress={ this.onPress }
  >
    <ScrollView contentContainerStyle={ cardStyle }>
      <Image
        resizeMode="cover"
        style={ imageStyle }
        source={ { uri: img_url } }
      />

      <View style={ titleWrapStyle }>
        <Text style={ textStyle }>{ title }</Text>
      </View>
    </ScrollView>
  </TouchableOpacity>

I am building cards that are absolutely positioned one behind another.我正在构建绝对一个接一个地放置的卡片。 These cards can then be swiped up or down using the panResponder .然后可以使用panResponder向上或向下滑动这些卡片。 But, on tapping the screen I am supposed to show a detail page on the same screen.但是,在点击屏幕时,我应该在同一屏幕上显示一个详细信息页面。

Now, I can detect the tap, but whenever the user taps/clicks, I want to disable the panResponder so that the card cannot be swiped and the user can scroll through the content.现在,我可以检测到点击,但是每当用户点击/点击时,我想禁用panResponder以便无法刷卡并且用户可以滚动浏览内容。 Once, the user scrolls to the end, I want re-enable swiping ie I want to enable panning.有一次,用户滚动到最后,我想重新启用滑动,即我想启用平移。

I know that onStartShouldSetResponder: () => false disables panResponder but how do we disable it after an instance is created.我知道onStartShouldSetResponder: () => false禁用panResponder但我们如何在创建实例后禁用它。 I couldn't find much about it else where.我在其他地方找不到太多关于它的信息。

For someone who will be looking how to temporarily disable PanResponder, below is my solution.对于将要寻找如何暂时禁用 PanResponder 的人,以下是我的解决方案。

Like @RaHuL - House Javascript noticed, the other answer doesn't really solve the problem because setting onStartShouldSetResponder to value corresponding to some state value which might change from true to false won't affect PanResponder (at least it seems so) if it was created with true .就像@RaHuL - House Javascript 注意到的那样,另一个答案并没有真正解决问题,因为将onStartShouldSetResponder设置为对应于某个状态值的值,该值可能从 true 变为 false 不会影响 PanResponder(至少看起来是这样)如果它是用true创建。

I solved similar problem by changing onPanResponderMove function.我通过更改onPanResponderMove函数解决了类似的问题。 I have a value inside state: panResponderEnabled and my function looks like this:我在 state 中有一个值: panResponderEnabled ,我的函数如下所示:

 onPanResponderMove: ( event, gesture ) => {
    if(this.state.panResponderEnabled){
       this.position.setValue( { x: 0, y: gesture.dy } ); 
    }
}

When I don't want to read changes from PanRespoder I just set panResponderEnabled to false.当我不想从 PanRespoder 读取更改时,我只需将panResponderEnabled设置为 false。

I think I found a way to disable PanResponder temporarily using onStartShouldSetResponder.我想我找到了一种使用 onStartShouldSetResponder 暂时禁用 PanResponder 的方法。 The goal is to toggle between true and false, even though it doesn't seem to respond to changes in state values.目标是在 true 和 false 之间切换,即使它似乎不响应状态值的变化。 If you're using functional components, the hook useRef seems to do the trick.如果您使用功能组件,钩子useRef似乎可以解决问题。

const [panResponderEnabled, _setPanResponderEnabled] = useState(true)

const panResponderEnabledRef = useRef(panResponderEnabled)
const setPanResponderEnabled = data => {
  panResponderEnabledRef.current = data
  _setPanResponderEnabled(data)
}

Then when you create your PanResponder:然后当你创建你的 PanResponder 时:

onStartShouldSetPanResponder: () => panResponderEnabledRef.current,

If you want a really simple brute force solution use the pointerEvents prop on the animated view.如果您想要一个非常简单的蛮力解决方案,请在动画视图上使用pointerEvents道具。

pointerEvents={stopPan ? 'none' : 'auto'}

This will stop all touch events on the view and all below it firing while stopPan is true.这将停止视图上的所有触摸事件,并且在stopPan为真时触发它下面的所有事件。

Instead of the arrow function for onStartShouldSetResponder you can use class function and use state to return true/false.代替onStartShouldSetResponder的箭头函数,您可以使用类函数并使用状态返回真/假。 Something like this像这样的东西

 constructor( props ) {
    super( props );
    this.state = {
      panResponderEnabled: true
    }
    this.position = new Animated.ValueXY();

    this.panResponder = PanResponder.create( {
      onStartShouldSetPanResponder: ( ) => true,
      onPanResponderMove: ( event, gesture ) => {
        this.position.setValue( { x: 0, y: gesture.dy } );
      },
      onPanResponderRelease: ( event, gesture ) => {
        if ( gesture.dy > SWIPE_THRESHOLD ) {
          this.forceSwipe( 'up' );
        } else if ( gesture.dy < -SWIPE_THRESHOLD ) {
          this.forceSwipe( 'down' );
        } else {
          this.resetPosition();
        }
      },
      onMoveShouldSetPanResponderCapture: ( evt, gestureState ) =>
      gestureState.dx !== 0 && gestureState.dy !== 0,
    } );
  }

  handlePanResponderStart = () => {
    return this.state.panResponderEnabled;
  }
  onCardPress = () => {
    this.setState({
      panResponderEnabled: false
    });
  }
  getCardStyle() {
    return {
      ...this.position.getLayout(),
    };
  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM