简体   繁体   English

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

[英]PanResponder snaps Animated.View back to original position on second drag

I have created a PanResponder to move a Animated.View vertically. 我创建了一个PanResponder来垂直移动Animated.View When I move it from it's original position it works fine, but once I go to move it for a second time it snaps back to its original position and then moves relative to the touch. 当我从它的原始位置移动它时,它工作正常,但是一旦我再次移动它,它会快速回到原来的位置,然后相对于触摸移动。

I am unpacking the responder straight into the Animated.View , could this be causing this behaviour somehow? 我正在将响应者直接解压缩到Animated.View ,这是否会导致这种行为?

Here is how I define my PanResponder: 以下是我定义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) => {
      ...
    }     
})

And applying the responder to my Animated.View : 并将响应程序应用于我的Animated.View

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

Thanks 谢谢

First, let's look at why this is happening: 首先,让我们来看看为什么会这样:

  • Your onPanResponderMove callback reads the gesture's dy (delta Y), which gives you the amount of pixels moved vertically since the beginning of the gesture. 你的onPanResponderMove回调读取手势的dy (delta Y),它给出了自手势开始以来垂直移动的像素数量。 This means that every time you start a new gesture, the delta starts from 0. 这意味着每次开始新手势时,delta都从0开始。

  • AnimatedXY#getLayout() on the other hand simply maps the y value to style property top . 另一方面, AnimatedXY#getLayout()只是将y值映射到样式属性top This means that when y is set to 0 in the beginning of the touch, the element will bounce back to its initial, non-offset position. 这意味着当在触摸开始时将y设置为0时,元素将弹回到其初始的非偏移位置。

In order to preserve the offset from the previous drag, you can use setOffset to preserve the previous offset position, and then setValue to reset the initial delta to 0. This can be done when the gesture starts, eg on onPanResponderGrant : 为了保留前一次拖动的偏移量,您可以使用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 }
  ])
});

As you can see, we are using a "private" method __getValue() here. 如您所见,我们在这里使用“私有”方法__getValue() Generally, syncronously reading the value of an Animated.value is not recommended, because the animation may be offloaded onto the native thread and the value may not be up to date. 通常,不建议同步读取Animated.value的值,因为动画可能会卸载到本机线程上,并且值可能不是最新的。 Here, at the beginning of the gesture, it should be safe though. 在这里,在手势的开头,它应该是安全的。

As a side note, since you are only moving the element on the Y axis, you don't necessarily need to use the two-dimensional Animated.ValueXY , since a basic Animated.Value will suffice. 作为旁注,由于您只是在Y轴上移动元素,因此您不一定需要使用二维Animated.ValueXY ,因为基本的Animated.Value就足够了。 If you refactor your code to use Value, you can just call drag.extractOffset() to reset the offset. 如果重构代码以使用Value,则可以调用drag.extractOffset()来重置偏移量。 It does the same thing, but does not appear to be available on AnimatedXY . 它做了同样的事情,但似乎没有在AnimatedXY上可用。

You just need to adjust the offset in onPanResponderGrant , like 你只需要在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})

      },

But also make sure you flatten the offset when the panResponder is released, or else it will have some glitch (the position will be reset according to previous offset) when you drag for the 3rd or 4th time. 但是当释放panResponder时也要确保平移偏移,否则当你拖动第3次或第4次时它会有一些毛刺(位置将根据先前的偏移重置)。

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

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

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