javascript - 使用hooks时如何为panResponder设置Offset?

标签 javascript reactjs react-native react-hooks drag-and-drop

我找到了一个代码示例,演示了如何使用 panResponder 在 React Native 中进行拖放操作。您可以尝试以下小吃中的代码:

https://snack.expo.io/S14RvxJ_L

我面临的问题是,如果您将项目放在放置区域中然后触摸它,则位置始终会重置。

我希望用户能够将项目拖离放置区域而不会出现此问题。 再次澄清一下:您将项目拖到放置区域,它将被涂成红色。现在再次拖动该项目并尝试拖动到您想要的任何位置,位置将被重置。 我尝试用钩子(Hook)设置圆圈的初始位置,尝试用起始值设置手势的 y0 和 x0 。目前还没有成功。

到目前为止我发现,我可以在 onPanResponderGrant 中使用 pan.setOffset() 。但由于平底锅是使用 useRef() 创建的,因此它是可变的并且无法更改,或者更好的是我不知道如何更改。

我如何以最好的方式实现这一目标?

import React from 'react';
import { StyleSheet, View, Text, Dimensions, Animated, PanResponder } from 'react-native';

export default function Drag() {
  const dropZoneValues = React.useRef(null);
  const pan = React.useRef(new Animated.ValueXY());
  const [bgColor, setBgColor] = React.useState('#2c3e50');

  const isDropZone = React.useCallback((gesture) => {
    const dz = dropZoneValues.current;
    return gesture.moveY > dz.y && gesture.moveY < dz.y + dz.height;
  }, []);

  const onMove = React.useCallback((_, gesture) => {
    if (isDropZone(gesture)) setBgColor('red');
    else setBgColor('#2c3e50');
  }, [isDropZone]);

  const setDropZoneValues = React.useCallback((event) => {
    dropZoneValues.current = event.nativeEvent.layout;
  });

  const panResponder = React.useMemo(() => PanResponder.create({
    onStartShouldSetPanResponder: () => true,

    onPanResponderMove: Animated.event([null, {
      dx  : pan.current.x,
      dy  : pan.current.y
    }], {
      listener: onMove
    }),
    onPanResponderRelease: (e, gesture) => {
      if (!isDropZone(gesture)) {
        Animated.spring(
          pan.current,
          {toValue:{x:0,y:0}}
        ).start();
      }
    }
  }), []);

  return (
    <View style={styles.mainContainer}>
      <View
        onLayout={setDropZoneValues}
        style={[styles.dropZone, {backgroundColor: bgColor}]}
      >
        <Text style={styles.text}>Drop me here!</Text>
      </View>
      <View style={styles.draggableContainer}>
        <Animated.View
          {...panResponder.panHandlers}
          style={[pan.current.getLayout(), styles.circle]}
        >
          <Text style={styles.text}>Drag me!</Text>
        </Animated.View>
      </View>
    </View>
  );
}

let CIRCLE_RADIUS = 36;
let Window = Dimensions.get('window');
let styles = StyleSheet.create({
  mainContainer: {
    flex: 1
  },
  dropZone: {
    height  : 100,
    backgroundColor:'#2c3e50'
  },
  text        : {
    marginTop   : 25,
    marginLeft  : 5,
    marginRight : 5,
    textAlign   : 'center',
    color       : '#fff'
  },
  draggableContainer: {
    position    : 'absolute',
    top         : Window.height/2 - CIRCLE_RADIUS,
    left        : Window.width/2 - CIRCLE_RADIUS,
  },
  circle: {
    backgroundColor     : '#1abc9c',
    width               : CIRCLE_RADIUS*2,
    height              : CIRCLE_RADIUS*2,
    borderRadius        : CIRCLE_RADIUS
  }
});

(代码来自:https://github.com/facebook/react-native/issues/25360#issuecomment-505241400)

最佳答案

终于解决了

您可以在此处查看结果:https://snack.expo.io/Bky!LlqbI

您必须在 onPanResponderGrant 中使用 setOffset 和 setValue。 pan 是一个可变对象,但仍然可以使用 pan.current.setOffset() 或 pan.current.setValue() 进行更改。最后,我必须将 pan.current.flattenOffset 添加到 onPanResponderRelease,以便为放置区域中的下一次拖动保留该位置。

关于javascript - 使用hooks时如何为panResponder设置Offset?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59784486/

相关文章:

node.js - 使用reactify是否需要安装 `node-jsx`

reactjs - React-Apollo 中 Compose 的替代方案是什么?

reactjs - 当状态发生变化时,如何正确更新 react native 滑动器组件?

react-native - 在 xcode 中运行 react native,我的错误屏幕是白色的。看不到错误信息

javascript - 使用变量通过 JavaScript 设置 SVG 属性

javascript - 当路由更改时,import css 仍然停留在页面中

javascript - 为什么我不能同时运行这两个 javascript? (平滑滚动和固定页脚)

android - 无法安装 react-native Nativebase : Execution failed for task ':app:compileDebugJavaWithJavac'

javascript - 如何从 Ajax 响应重新填充 jquery UI 日期选择器

javascript - 当改变另一个输入时如何获取上面的输入值