Animated.decay
decay典型的使用场景是某个以组件一定的速度运行并不断减速,比如,移动(swipe或者fling)一张卡片。手指让卡片滑动并具有速度,最后卡片会因为阻力减速,并最终停止。
如果没有decay的话,那么手指停在哪里,卡片就会停在哪里。来看看如何使用:
this._animatedValue = new Animated.ValueXY();
Animated.decay(this._animatedValue, { // coast to a stop
velocity: {x: gestureState.vx, y: gestureState.vy}, // velocity from gesture release
deceleration: 0.997,
})
这个效果实现出来会使什么样子的呢?幸好Brent Vatne已经做好了一个。你可以到这里看看他是如何实现的:https://github.com/brentvatne/react-native-animated-demo-tinder/blob/master/index.ios.js#L47。
this._panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value});
this.state.pan.setValue({x: 0, y: 0});
},
onPanResponderMove: Animated.event([
null, {dx: this.state.pan.x, dy: this.state.pan.y},
]),
onPanResponderRelease: (e, {vx, vy}) => {
this.state.pan.flattenOffset();
var velocity;
if (vx >= 0) {
velocity = clamp(vx, 3, 5);
} else if (vx < 0) {
velocity = clamp(vx * -1, 3, 5) * -1;
}
if (Math.abs(this.state.pan.x._value) > SWIPE_THRESHOLD) {
Animated.decay(this.state.pan, {
velocity: {x: velocity, y: vy},
deceleration: 0.98
}).start(this._resetState)
} else {
Animated.spring(this.state.pan, {
toValue: {x: 0, y: 0},
friction: 4
}).start()
}
}
})
注意:最好是不要响上例总一样直接存取Animated.Value
的值,如:_value
。这是同步取值,而且会导致效率问题(不过现在Animated动画已经不支持同步取值了)。最好是添加一个事件监听器。
主要看这个方法:
onPanResponderRelease: (e, {vx, vy}) => {
On the release we the second argument is the ending gestureState, we use destructing to pop off the velocities.
{vx, vy}
是结束时的手势,使用这个值来计算速度:
if (Math.abs(this.state.pan.x._value) > SWIPE_THRESHOLD) {
Animated.decay(this.state.pan, {
velocity: {x: velocity, y: vy},
deceleration: 0.98
}).start(this._resetState)
} else {
如果用户移动卡片到某个阈值的时候(无论左右)我们会继续执行动画,知道停止。