PanResponder在第二次拖动时将Animated.View捕捉回原始位置

时间:2017-02-02 23:41:55

标签: javascript reactjs react-native

我创建了一个PanResponder来垂直移动Animated.View。当我从它的原始位置移动它时,它工作正常,但是一旦我再次移动它,它会快速回到原来的位置,然后相对于触摸移动。

我正在将响应者直接解压缩到Animated.View,这是否会以某种方式导致此行为?

以下是我定义PanResponder的方法:

this.state = {                            
  drag: new Animated.ValueXY()            
}                                         

this._responder = PanResponder.create({                                              
    onStartShouldSetPanResponder: () => true,                             
    onPanResponderMove: Animated.event([null, {                           
      dy: this.state.drag.y                                             
    }]),                                                                  
    onPanResponderRelease: (e, coords) => {
      ...
    }     
})

将响应者应用于我的Animated.View

<Animated.View {...this._responder.panHandlers} style={this.state.drag.getLayout()}>
  // children go here
</Animated.View>                 

谢谢

2 个答案:

答案 0 :(得分:8)

首先,让我们来看看为什么会这样:

  • 您的onPanResponderMove回调会读取手势的dy(增量Y),它会为您提供自手势开始以来垂直移动的像素数量。这意味着每次开始新手势时,增量都从0开始。

  • 另一方面,
  • AnimatedXY#getLayout()只是将y值映射到样式属性top。这意味着当触摸开始时y设置为0时,元素将弹回到其初始的非偏移位置。

为了保留上一次拖动的偏移量,您可以使用setOffset保留先前的偏移位置,然后使用setValue将初始增量重置为0.这可以在手势开始,例如在onPanResponderGrant

this._responder = PanResponder.create({
  onStartShouldSetPanResponder: () => true,
  onPanResponderGrant: (evt, gestureState) => {
    this.state.drag.setOffset(this.state.drag.__getValue());
    this.state.drag.setValue({ x: 0, y: 0 });
  },
  onPanResponderMove: Animated.event([
    null,
    { dy: this.state. drag.y }
  ])
});

如您所见,我们在这里使用“私有”方法__getValue()。通常,不建议同步读取Animated.value的值,因为动画可能会卸载到本机线程上,并且值可能不是最新的。在这里,在手势开始时,它应该是安全的。

作为旁注,由于您只是在Y轴上移动元素,因此您不一定需要使用二维Animated.ValueXY,因为基本Animated.Value就足够了。如果您重构代码以使用Value,则只需调用drag.extractOffset()即可重置偏移量。它做同样的事情,但在AnimatedXY上似乎没有。

答案 1 :(得分:2)

您只需要调整onPanResponderGrant中的偏移量,例如

   onPanResponderGrant: (e, gestureState) => {
          this.state.drag.setOffset({x: this.state.drag.x._value, y: this.state.drag.y._value});
          this.state.drag.setValue({x: 0, y: 0})

      },

但是也要确保在释放panResponder时平移偏移量,否则当你拖动第3次或第4次时它会有一些毛刺(位置将根据先前的偏移重置)。

  onPanResponderRelease: (e, {vx, vy}) => {
        this.state.drag.flattenOffset()      
   }