PanResponder
当需要把拖动(pan手势)和动画关联的时候,就需要用到PanResponder
了。它可以控制动画的执行,或者在结束pan手势的时候结束动画的执行。
强烈建议读者阅读手势识别系统和PanResponder相关的官方文档,这对下面的内容的理解非常有帮助。
PanResponder
中有三个方法需要关注。
1. onPanResponderGrant
方法定义:
onPanResponderGrant: (event, gestureState) => {...}
最开始动画的准备工作就在这里进行。我们可能会用到setOffset来处理拖动,处理情况不同会用到的方法也不一样。
2. onPanResponderMove
这个方法的定义是这样的:
onPanResponderMove: (event, gestureState) => {}
这个方法会在用户在屏幕上移动手指的时候调用。很多时候是一根手指在屏幕上滑动。这并不代表这个方法只能处理一个触摸。所以event(第一个参数)是一个数组,包含当前全部的触摸事件。
一般来说,这个方法里会用到Animated.event
。但是,如果你要处理非常复杂的动画,比如要根据当前触摸事件的数量不同展现不同的动画,那么涉及到的内容就会很多了。无论如何,你会跟踪用户的一个特定的触摸事件。
3. onPanResponderRelease
方法定义:
onPanResponderRelease: (event, gestureState) => {...}
在这里计算动画值和一些逻辑处理。比如Tinder,在用户的手指全部离开屏幕的时候需要计算卡片被拖动的最终位置。如果这个位置大于等于我们设定的某个阈值的时候,就会触发一个Animated.decay动画把卡片“扔”出屏幕。或者在卡片的位置小于阈值的时候,就用动画的方式把卡片恢复到屏幕中央的位置。这会用到Animated.timing和和Animated.spring。很多时候,Animated.flattenOffset也会用到。
还有一些情况需要关注。
- 处理
onPanResponderGrant
启动的动画。 - 根据从其他动画里获得的值(一般是通过addListener得到的)来决定如何做些什么,比如结束当前动画或者结束其他的动画等。
- 一般不会遇到。这个情况就是处理
onPanResponderTerminate
。就如文档中所说的:另外一个组件代替当前组件成为相应器,所以当前的手势全部被取消。你可以像处理onPanResponderRelease
一样处理onPanResponderTerminate
。你也可以选择重置动画。这就看你要实现的效果是什么样的了。