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

IT技术 javascript reactjs react-native
2021-05-10 14:51:01

我创建了一个 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个回答

首先,让我们看看为什么会发生这种情况:

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

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

为了保留上次拖动的偏移量,您可以使用setOffset来保留之前的偏移量位置,然后setValue将初始增量重置为 0。这可以在手势开始时完成,例如 on 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.

你只需要调整偏移量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 时将偏移展平,否则在第三次或第四次拖动时会出现一些故障(位置将根据先前的偏移重置)。

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