android 在LongPress类型事件上React Native激发,但用于拖动动作

dfddblmv  于 2022-11-03  发布在  Android
关注(0)|答案(1)|浏览(131)

我正在用React Native开发一个游戏。为了在四个基本方向中的一个方向上移动,玩家必须在屏幕上的任何地方滑动。到目前为止,我已经用下面的代码实现了这一点,它记录了手势开始的XY位置,然后在手势结束时根据这个位置进行一些计算。

<Pressable style={styles.container}
  onPressIn={e => {
    touchPos.current.y = e.nativeEvent.pageY;
    touchPos.current.x = e.nativeEvent.pageX;
  }}
  onPressOut={e => {
    const minDist = 50;
    const vertDist = touchPos.current.y - e.nativeEvent.pageY;
    const horizDist = touchPos.current.x - e.nativeEvent.pageX;

    // Then do some math and pass the swipe information on to game logic
  }}>
    {/* Some game components go here. */}
  </Pressable>

这很好用,但如果用户在某个方向滑动但没有抬起手指,游戏会在那个方向重复移动(例如,每500ms)直到他们抬起手指,那就更好了。不幸的是,如果用户在滑动动作中按住不放,onLongPress * 不会触发 *。它只有在用户按住不放 * 而没有 * 移动手指时才会触发。
我在网上搜索了一下,但也许我没有使用正确的术语来定义我的问题,因为我找不到任何提到类似问题的内容。关于Pressable的React Native文档也没有太大帮助。有一个属性pressRetentionOffset表示触摸在视图外多远仍然可以算作按下,但没有任何属性表示触摸在视图内移动多远仍然可以触发onLongPress
虽然这将是一个合适的解决方案,以弄清楚onLongPress,所有我真正需要的是一种方法,不断检查的X和Y位置的触摸元素被触摸。

owfi6suc

owfi6suc1#

所以我发现React Native的答案(没有依赖性)根本不涉及Pressable。相反,我们需要PanResponder。对于那些搜索这个问题的人来说,问题中描述的运动的正确术语不是拖动或滑动,而是平移。
至于解决方案,我们需要类似这样的东西(改编自使用模式here):

const panResponder = React.useRef(
  PanResponder.create({
    // Ask to be the responder:
    onStartShouldSetPanResponder: (evt, gestureState) => true,
    onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
    onMoveShouldSetPanResponder: (evt, gestureState) => true,
    onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
    onPanResponderTerminationRequest: (evt, gestureState) => true,
    onShouldBlockNativeResponder: (evt, gestureState) => true,

    onPanResponderGrant: (evt, gestureState) => {
      // The gesture has started. Since there is no built in 'onLongPress' type
      // event, we now start to keep track of time elapsed ourselves.
    },
    onPanResponderMove: (evt, gestureState) => {
      // The most recent move position is gestureState.moveX, gestureState.moveY
      // Distance moved is also helpful: gestureState.dx, gestureState.dy
      // Once sufficient time has passed, start handling the onLongPress 'drag'
    },
    onPanResponderRelease: (evt, gestureState) => {
      // The user has released all touches while this view is the
      // responder. This typically means a gesture has succeeded.
    },
    onPanResponderTerminate: (evt, gestureState) => {
      // Another component has become the responder, so this gesture
      // should be cancelled.
    },
  })
).current;

这实际上比onLongPress的平移功能要灵活得多,因为它为其他可能性打开了大门,比如在用户抬起手指完成移动之前预览移动,或者将其移回去取消移动。

相关问题